2009-07-15 11 views
3

Ich bin derzeit verwirrt von C#.C# -Aufruffunktion basierend auf Untertyp des Objekts

Ich habe eine Reihe von Klassen, sagen A, B und C, die alle aus der Klasse "Parent" stammen. Ich habe eine Funktion, die ein Argument des Typs Parent annimmt, und abhängig davon, mit welcher Kindklasse das Objekt, mit dem es aufgerufen wird, ist, möchte ich, dass es eine andere Methode aufruft.

Derzeit denke ich mit einem Wörterbuch Mapping-Typen zu Delegierten, aber das scheint albern, obwohl es ist alles, was ich im Moment kommen kann.

Das Problem ist, dass, wenn ich in der Funktion bin, ich nur weiß, dass es vom Typ Parent ist, und ich kann GetType verwenden, um zu bekommen, welche Kindklasse ich habe, die das Wörterbuch erlauben würde. Sonst würde ich wahrscheinlich Funktionsüberladung verwenden.

Wirklich Typcasting scheint wie die beste Methode, so dass ich Funktion Überladung verwenden kann, die viel weniger wortreich wäre, aber ich weiß nicht, wie ich es tun könnte oder ob es überhaupt funktionieren würde.

Irgendwelche Empfehlungen?

+0

Leider habe ich keine Kontrolle über die Objekte in Frage, so dass ich Methoden zu ihnen hinzufügen kann. Wahrscheinlich wäre das der richtige Weg. Ich schaute in das Dictionary der Delegierten, aber es lässt eine Menge Boilerplate Typ Umwandlung Code. Also habe ich eine Frage zum Aufruf überladener Funktionen mit Typecasting Generics gestellt. – AlexH

Antwort

1

Overloading ist der richtige Weg

public void DoWork(Parent obj) 
{ 
    if(obj is A) 
    Foo((A)obj); 

    else if(obj is B) 
    Foo((B)obj); 

    else 
    Foo(obj); 
} 

public void Foo(Parent obj) 
{ 
    //Do something for parent 
} 

public void Foo(A obj) 
{ 
    //Do something for A 
} 

public void Foo(B obj) 
{ 
    //Do something for B 
} 

oder wenn Sie nicht wollen, werfen das Objekt explizit für jeden Typ Sie Reflektion verwenden könnte wie dies:

Bar methodObject = new Bar(); 
MethodInfo method = methodObject.GetType().GetMethod(
      "Foo", new Type[] { obj.GetType()}); 

method.Invoke(methodObject, new object[]{obj}); 
7

Haben die Methoden alle dieselbe Signatur? Wenn ja, macht es zu einer virtuellen (potentiell Abstract) Methode in der übergeordneten Klasse:

using System; 

public abstract class Parent 
{ 
    public abstract void DoSomething(); 
} 

public class A : Parent 
{ 
    public override void DoSomething() 
    { 
     Console.WriteLine("A.DoSomething()"); 
    } 
} 

public class B : Parent 
{ 
    public override void DoSomething() 
    { 
     Console.WriteLine("B.DoSomething()"); 
    } 
} 

public class Test 
{ 
    static void Main() 
    { 
     Parent a = new A(); 
     Parent b = new B(); 
     a.DoSomething(); 
     b.DoSomething(); 
    } 
} 

Ist dies nicht geeignet ist, dann double dispatchkann geeignet sein, aber ich würde wirklich wissen muß mehr über die Situation ... könnte es sein, dass die Änderung eines Teils des bestehenden Designs besser funktioniert.

+0

@Downvoter: Interessieren Sie sich für einen Kommentar? –

2

Dies scheint eine perfekte Anwendung für das Besuchermuster, wenn Sie nicht eine virtuelle Methode, um Eltern, und außer Kraft setzen in A, B und C

+0

Sicher, wenn Doppelversand benötigt wird, aber es ist nicht klar, ob es ist. Ich vermute nicht. –

+0

Ich schlage nicht doppelten Versand vor. Wollten Sie John Skeets Beitrag kommentieren? –

+0

Das Besuchermuster ist doppelter Versand. – munificent

0

Ist der Name der Methode unterschiedlich hinzufügen können? Oder ist es eine andere Implementierung der gleichen Methode?

Wenn der Name der Methode identisch ist, können Sie override verwenden. Wenn es nur eine untergeordnete Methode geben soll, sollte die übergeordnete Methode zusätzlich als abstrakt markiert werden.

EDIT: mit dem Code ...

public abstract class parentClass 
{ 
    //...other stuff... 
    protected abstract void doSomething(); //or use virtual instead of abstract and give the method a body 
} 

public class childClass : parentClass 
{ 
    //...other stuff... 
    protected override void doSomething() 
    { 
     //...do something 
    } 
} 
Verwandte Themen