Frage

Ich habe den Begriff gehört/gelesen, verstehe aber nicht ganz, was er bedeutet.

Wann sollte ich diese Technik anwenden und wie würde ich sie anwenden?Kann jemand ein gutes Codebeispiel bereitstellen?

War es hilfreich?

Lösung

Das Besuchermuster ist eine Möglichkeit, objektorientiert einen doppelten Versand durchzuführen.

Dies ist nützlich, wenn Sie die für ein bestimmtes Argument zu verwendende Methode basierend auf dessen Typ zur Laufzeit und nicht zur Kompilierungszeit auswählen möchten.

Ein Sonderfall ist der Doppelversand Mehrfachversand.

Wenn Sie eine virtuelle Methode für ein Objekt aufrufen, wird dies als Single-Dispatch betrachtet, da die tatsächliche Methode, die aufgerufen wird, vom Typ des einzelnen Objekts abhängt.

Beim Double Dispatch werden sowohl der Objekttyp als auch der Typ des einzigen Arguments der Methode berücksichtigt.Dies ähnelt der Auflösung einer Methodenüberladung, außer dass der Argumenttyp zur Laufzeit im Double-Dispatch und nicht statisch zur Kompilierungszeit bestimmt wird.

Beim Mehrfachversand können einer Methode mehrere Argumente übergeben werden, und welche Implementierung verwendet wird, hängt vom Typ jedes Arguments ab.Die Reihenfolge, in der die Typen ausgewertet werden, hängt von der Sprache ab.In LISP wird jeder Typ vom ersten bis zum letzten überprüft.

Sprachen mit Mehrfachversand nutzen generische Funktionen, bei denen es sich lediglich um Funktionsdeklarationen handelt und nicht um generische Methoden, die Typparameter verwenden.

Double-Dispatch in C# durchführen, können Sie eine Methode mit einem einzigen Objektargument und dann bestimmte Methoden mit bestimmten Typen deklarieren:

using System.Linq;  

class DoubleDispatch
{ 
    public T Foo<T>(object arg)
    { 
        var method = from m in GetType().GetMethods()
                   where    m.Name == "Foo" 
                         && m.GetParameters().Length==1
                         && arg.GetType().IsAssignableFrom
                                           (m.GetParameters()[0].GetType())
                         && m.ReturnType == typeof(T)
                   select m;

        return (T) method.Single().Invoke(this,new object[]{arg});          
    }

    public int Foo(int arg) { /* ... */ }

    static void Test() 
    { 
        object x = 5;
        Foo<int>(x); //should call Foo(int) via Foo<T>(object).
    }
}       

Andere Tipps

Hallo Leute, der von Mark gepostete Code ist nicht vollständig und was auch immer da ist, funktioniert nicht.

So optimiert und vollständig.

class DoubleDispatch
{
    public T Foo<T>(object arg)
    {
        var method = from m in GetType().GetMethods(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic)
                     where m.Name == "Foo"
                           && m.GetParameters().Length == 1
                           //&& arg.GetType().IsAssignableFrom
                           //                  (m.GetParameters()[0].GetType())
                           &&Type.GetType(m.GetParameters()[0].ParameterType.FullName).IsAssignableFrom(arg.GetType())
                           && m.ReturnType == typeof(T)
                     select m;


        return (T)method.Single().Invoke(this, new object[] { arg });
    }

    public int Foo(int arg)
    {
        return 10;
    }

    public string Foo(string arg)
    {
        return 5.ToString();
    }

    public static void Main(string[] args)
    {
        object x = 5;
        DoubleDispatch dispatch = new DoubleDispatch();

        Console.WriteLine(dispatch.Foo<int>(x));


        Console.WriteLine(dispatch.Foo<string>(x.ToString()));

        Console.ReadLine();
    }
}

Vielen Dank an Mark und andere für die nette Erklärung zum Double-Dispatcher-Muster

C# 4 führt den Pseudotyp ein dynamic Dadurch wird der Funktionsaufruf zur Laufzeit (anstelle der Kompilierungszeit) aufgelöst.(Das heißt, der Laufzeittyp des Ausdrucks wird verwendet).Doppelter (oder mehrfacher) Versand kann wie folgt vereinfacht werden:

class C { }

static void Foo(C x) => Console.WriteLine(nameof(Foo));
static void Foo(object x) => Console.WriteLine(nameof(Object));

public static void Main(string[] args)
{
    object x = new C();

    Foo((dynamic)x); // prints: "Foo"
    Foo(x);          // prints: "Object"
}

Beachten Sie auch die Verwendung dynamic Sie verhindern, dass der statische Analysator des Compilers diesen Teil des Codes untersucht.Daher sollten Sie den Einsatz sorgfältig abwägen dynamic.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top