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.
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.