2016-03-23 3 views
-1

Ich habe eine öffentliche statische Klasse namens Router mit einigen Formularreferenzen wie diesem;Wie kann ich eine Formularreferenz von einer Klasse anhand des Namens mithilfe von Reflektion in C# abrufen?

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

Ich versuche, eine Funktion namens „Route“ zu schaffen - diese Funktion wird ein String-Parameter nehmen, die mindestens eines dieser Form Referenzen übereinstimmen. Bei Übereinstimmung wird das ausgewählte Formular mit der Methode "Index()" aufgerufen. (Jedes Formular hat einen Index() pre-built, ich brauche es nur genannt)

Es gibt nicht viel zu sagen über den Zweck dieser anderen als die Tatsache, dass ich eine MVC-ähnliche Struktur für eine sehr erstellen bestimmter Grund. So können alle anderen Vorschläge geschätzt werden. Um zusammenzufassen, muss ich die korrekte Formularreferenz nach Namen finden, d. H. "RLogin" mit einem Parameter in die "Route" -Methode übergeben, die schließlich die Funktion "Index()" auf diesem Formular aufrufen wird.

Ich verstehe, dass dies mit Reflection möglich sein kann und ich ein bisschen mit anderen Beispielen verwechselt wurde.

Danke.

Antwort

1

Dies klingt eine gute Verwendung für die Abhängigkeit-Injektion. Anstatt dem Router einen String-Verweis der zu verwendenden Klasse zu geben, geben Sie ihm einfach eine Instanz der Klasse innerhalb des Konstruktors.

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

Wie erstelle ich den Router jetzt? Zum Beispiel mit einem FormFactory und dann rufen Sie 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: Sie können erweitern Fabrik auch die Instanzen zu erstellen, die nur durch ihren Namen:

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

aber darüber im Klaren sein, dass dies den Workflow für dynamischen Montage-Laden mit einem vollständig qualifizierten folgt typename und der Assemblyname auch. See here wie CreateInstance verwendet wird.

EDIT2: als Ihrer bearbeiten möchten, dass Sie nur eine Instanz pro Klasse haben, um durch den Router zurückgeführt werden, so dass Sie die Formulare als Singletons entwerfen können:

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

    private frmLogin() { } 
} 

Jetzt ist die Fabrik-Methode leicht verändert zu etwas wie das:

+0

Also würde ich es implementieren: Router obj = neue Router (frmWhatever); und es würde instanziieren und rufen Sie die Index-Funktion ... Aber nicht auf diese Weise ein Objekt erstellen jedes Mal, wenn ich auf ein anderes Formular route? Ich brauche nur einmal die Methode "Index()" des Formulars.Ich werde niemals andere Eigenschaften oder Methoden in diesem Objekt verwenden. Außerdem versuche ich, diese einzelne "Route" -Funktion für mehrere mögliche Klassennamen wiederzuverwenden, und alles, womit ich arbeiten muss, ist die Zeichenfolge auf der Schaltfläche, die angeklickt wurde, die bestimmt, was der Benutzer zu routen möchte, und so hatte ich gehofft, dass die entsprechende Klasse gefunden werden konnte. –

+0

Sie wollen also sicherstellen, dass jede Klassen-Index-Methode genau einmal aufgerufen wird? Dann können Sie diese Funktionalität innerhalb der Factory anstelle des Routers-Konstruktors hinzufügen. Einfach die Index-Methode statisch machen und in den verschiedenen Fällen aufrufen: 'frmLogin.Index()'. Überprüfen Sie innerhalb der Methode, ob sie bereits mit einer statischen Variablen in der Klasse selbst aufgerufen wurde. – HimBromBeere

+1

@BarryD. Wenn Sie eine Zuordnung von einer Zeichenkette zu einer Form wünschen, verwenden Sie einfach Dictionary '. Aber ich würde das so schnell wie möglich tun, um den "nicht sicheren" Weg so klein wie möglich zu halten :) – Luaan

1

Hier ist eine Lösung mit Reflexion, dennoch empfehle ich, eine mehr typsichere Ansatz wie die bereits gepostet zu verwenden.

Es erstellt ein Dictionary mit jedem Feldnamen und einem Delegaten, das auf die entsprechende Indexmethode verweist, so dass die Reflektionsleistung während des cctor-Laufs nur einmal getroffen wird.

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

Dies würde die 'Index'-Methode bei jedem Aufruf von' Route' aufrufen, was ich soweit verstanden habe, möchte das OP vermeiden (siehe die Kommentare in meiner Antwort). Aber coole Lösung. + 1 – HimBromBeere

+0

Ja, ich sehe, vielleicht kann das OP seine Bedürfnisse klären, indem es das ganze Szenario in seiner Frage zur Verfügung stellt. – thehennyy

+0

@thehennyy Nein, das funktioniert. Was ich vermeide, ist ein neues Objekt, das für jedes Routing erstellt wird. Natürlich muss der Index auf jedem Routing aufgerufen werden, sonst welche Funktionalität hat Routing? Danke für diesen Beitrag. :) –