简体   繁体   中英

How can I get a form reference from a class by name using reflection in C#?

I have a public static class called Router with some form references like this;

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

I am trying to create a function called "Route" - this function will take a string parameter, which will match at least one of those form references. When matched, the selected form will have its "Index()" method invoked. (Every form has an Index() pre-built, I just need it called)

There's not too much to say about the purpose of this other than the fact that I'm creating an MVC-like structure for a very specific reason. So any other suggestions may be appreciated.


To summarise, I need to find the correct Form reference by name ie "rLogin" using a parameter passed into the "Route" method, which will eventually call the "Index()" function on that form.

I understand this may be possible with Reflection and I got a bit confused with other examples.

Thanks.

This sounds a good use for dependency-injection. Instead of giving the router a string-reference of the class to be used, why not simply give it an instance of the class itself within the constructor?

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();
    }      
}

How to create the router now? For example by using a FormFactory and then call 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();
        }
    }    
}

EDIT: You may also extend your factory to create the instances only by their name:

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

But be aware that this will follows the workflow for dynamical assembly-loading including a fully-qualified typename and the assembly-name also. See here how CreateInstance is used.

EDIT2: as of your edit you want to have only one instance per class to be returned by the router, so you may design the forms as singletons:

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

    private frmLogin() { }
}

Now the factory-method slightly changes to something like this:

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

Here is a solution using reflection, nevertheless i recommend to use a more typesafe approach like the one already posted.

It creates a dictionary with each fieldname and a delegate pointing to its corresponding index method, so you will have the reflection performance hit only once during the cctor run.

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]();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM