2013-06-10 4 views
7

Ich habe ähnliche Fragen/Antworten für diese in der Vergangenheit geschrieben gesehen, aber meins unterscheidet sich leicht von den anderen, die ich gesehen habe.Dynamische Auswahl der Methode basierend auf Laufzeit-Parameter Typ

Im Wesentlichen habe ich eine gemeinsame Schnittstelle und mehrere Klassen, die davon implementieren/erben. Dann habe ich in einer separaten Klasse Methoden, die auf Objekte einwirken müssen, die vom Interface IObject angegeben werden. Auf jeden von ihnen muss jedoch auf unterschiedliche Weise reagiert werden, weshalb es eine separate Deklaration der Methode für jeden konkreten Typ gibt, der IObjekt erweitert.

class IObject 
{ 
    ... 
} 

class ObjectType1 : IObject 
{ 
    ... 
} 

class ObjectType2 : IObject 
{ 
    ... 
} 

class FooBar 
{ 
    void Foo (ObjectType1 obj); 
    void Foo (ObjectType2 obj); 
} 

Nun zu mir, eine offensichtlichen Lösung ist, indem die Methode Foo innerhalb jeder einzelnen Klasse Vorteile der dynamischen Bindung zu nehmen, die zur Laufzeit automatisch auszuführen, um die richtig Foo wählen würden. Dies ist jedoch eine Option hier, weil ich mehrere Modelle für das Verhalten auf diese Objekte definieren, und ich würde lieber jedes einzelne Modell für die Handhabung von Objekten in seiner eigenen Klasse einkapseln, anstatt alle Modelle in die Objektklassen.

Ich fand this Beitrag, der zeigt, wie man ein Wörterbuch verwendet, um zur Laufzeit die korrekte Methodenimplementierung dynamisch auszuwählen. Mir geht es gut mit diesem Ansatz; Nehmen wir jedoch an, dass ich in jedem Modell einen solchen Versand einmal durchführen muss. Wenn ich nur IObject und seine konkreten Implementierungen habe, gibt es irgendeine Möglichkeit, diesen Ansatz zu verallgemeinern, so dass ich Methoden beliebigen Namens basierend auf dem Laufzeittyp der Objekte aufrufen konnte?

Ich weiß, das ist wahrscheinlich eine unklare Frage, aber ich würde jede Hilfe sehr schätzen.

Antwort

10

Das dynamic Schlüsselwort ist eigentlich wirklich gut auf diese:

void Main() 
{ 
    var foobar = new FooBar(); 
    foreach(IObject obj in new IObject[]{ new ObjectType1(), new ObjectType2()}) 
    { 
     foobar.Foo((dynamic)obj); 
    } 
    // Output: 
    // Type 1 
    // Type 2 
} 

class IObject 
{ 
} 

class ObjectType1 : IObject 
{ 
} 

class ObjectType2 : IObject 
{ 
} 

class FooBar 
{ 
    public void Foo (ObjectType1 obj) { 
     Console.WriteLine("Type 1"); 
    } 
    public void Foo (ObjectType2 obj) { 
     Console.WriteLine("Type 2"); 
    } 
} 

Der Code ist super-einfach, und es ist pretty decent performance bekam.

+0

Das ist die richtige Antwort, denke ich. – Ziffusion

+1

Oh wow, wenn sich das so verhält, wie es aussieht, dann ist das großartig! Ich werde ein wenig herumspielen, wenn ich eine Chance bekomme, aber danke für diese Lösung. Der Fokus in meinem Code liegt auf der Lesbarkeit und einfachen Wartung, so dass dies ziemlich erstaunlich aussieht. – TSM

2

Vielleicht möchten Sie etwas sehr nah an visitor patter.

Wenn Sie nur eine Methode (Foo) ein Objekt wählen wollen (FooBar) durch Argumenttyp Sie Reflektion verwenden können alle Methoden mit Vornamen (Foo) und machen manuelles Spiel von Argumente zu erhalten, basierend auf Objekttyp (ObjectTypeX) und die Wahl des Arguments. Vergessen Sie nicht, abgeleitete Klassen richtig zu behandeln.

Um Kosten der Reflexion bei jedem Aufruf zu vermeiden - Cache-Ergebnisse (d. H. Durch Erstellen/Kompilieren von Expression Tree).

Beachten Sie, dass Dictionary (Aktionen für angegebene Methodenname nach Typ indiziert) wahrscheinlich einfacher zu unterstützen/debug zu starten ist. Später, wenn Sie es langsam für Sie brauchen, können Sie es durch etwas komplizierter wie Reflexion ersetzen.

+0

Interessant, danke für die Rückmeldung!Ich bin mit dem Visitor Design Pattern leicht vertraut, aber ich bin sehr neu in C# und erkunde alle meine Möglichkeiten. – TSM

0

Sie können nur eine Methode machen, die die Schnittstelle Typ nimmt, dann überprüfen Sie die correcttype und warf es

ObjectType1 obj1 = new ObjectType1(); 

foo(obj1); 

void foo(IObject fm) 
     { 
      ObjectType1 cls; 
      if (fm is ObjectType1) 
      { 
       cls = fm as ObjectType1; 
       cls.ID = 10; 
       MessageBox.Show(cls.ID.ToString() + " " + cls.GetType().ToString()); 
      } 
     } 

das ist, weil die Klassen IObject implementieren ist cls.ID nur ein Beispiel Sie können setze eine Eigenschaft, die du implementierst. Bitte versuchen Sie es und lassen Sie mich wissen .... beste Wünsche.

+0

Dies war der Ansatz, den ich ein paar Tage zuvor gemacht habe (weil ich mich damit auskenne und eine Demo brauche). Jetzt, wo ich dieses Problem in größerem Umfang anwende, erkunde ich andere, einfachere Optionen, die möglicherweise spezifisch für C# sind. Dieser Ansatz funktioniert jedoch! – TSM

Verwandte Themen