如何使用C#中的反射按名称从类中获取表单引用



我有一个名为Router的公共静态类,其中包含一些类似的表单引用;

public static class Router
{
     static frmLogin rLogin = new frmLogin();
     static frmDashboard rDashboard = new frmDashboard();
     static frmReport rReport new frmReport();
}

我正在尝试创建一个名为"Route"的函数——这个函数将使用一个字符串参数,该参数将至少匹配其中一个表单引用。匹配时,所选表单将调用其"Index()"方法。(每个表单都预先构建了一个Index(),我只需要它被称为)

除了我创建一个类似MVC的结构是出于一个非常具体的原因之外,没有太多关于这个目的的话要说。因此,任何其他建议都将不胜感激。


总之,我需要通过名称找到正确的Form引用,即"rLogin",使用传递到"Route"方法的参数,该方法最终将调用该表单上的"Index()"函数。

我知道这可能与Reflection有关,我对其他例子有点困惑。

谢谢。

这听起来对依赖项注入很有用。与其给路由器一个要使用的类的字符串引用,为什么不简单地在构造函数中给它一个类本身的实例呢?

interface IForm { }
class frmLogin : Form, IForm { }
class frmDashboard: Form, IForm { }
class frmReport: Form, IForm { }
public class Router
{
    IForm form;
    public Router(IForm form)
    {
        this.form = form; 
        this.form.Index();
    }      
}

现在如何创建路由器?例如,通过使用FormFactory然后调用new Router(myFactory.CreateForm("frmLogin"))

class FormFactory {
    public IForm CreateForm(string name) {
        switch(name) {
            case: "frmLogin": return new frmLogin();
            case: "frmDashboard": return new frmDashboard();
            case: "frmReport": return new frmReport();
        }
    }    
}

编辑:您也可以扩展您的工厂,只通过它们的名称来创建实例:

public IForm CreateForm(string name) {
    return (IForm) Activator.CreateInstance(assembly, name);
}    

但请注意,这将遵循动态程序集加载的工作流,包括完全限定的类型名称和程序集名称。请参阅此处CreateInstance的使用方式。

EDIT2:在您编辑时,您希望每个类只有一个实例由路由器返回,因此您可以将表单设计为singletons:

class frmLogin : Form, IForm {
    public static readonly Instance = new frmLogin();
    private frmLogin() { }
}

现在工厂的方法稍微改变为这样:

var type = myAssembly.GetType(name);
return (IForm) type.GetField("Instance", BindingFlags.Public | BindingFlags.Static).GetValue(null);

这里有一个使用反射的解决方案,不过我建议使用一种更类型安全的方法,就像已经发布的方法一样。

它创建了一个字典,每个字段名和一个指向其相应索引方法的委托,因此在cctor运行期间,反射性能只会受到一次影响。

public static class Router
{
    static frmLogin rLogin = new frmLogin();
    static frmDashboard rDashboard = new frmDashboard();
    static frmReport rReport = new frmReport();
    static readonly Dictionary<string, Action> RoutingDictionary;
    static Router()
    {
        RoutingDictionary = typeof (Router).GetFields(BindingFlags.Static | BindingFlags.NonPublic)
            .Where(x => typeof (Form).IsAssignableFrom(x.FieldType))
            .ToDictionary(k => k.Name, v =>
            {
                var form = v.GetValue(null);
                return (Action) form.GetType().GetMethod("Index").CreateDelegate(typeof (Action), form);
            });
    }
    public static void Route(string form)
    {
        RoutingDictionary[form]();
    }
}