Question

J'ai entendu/lu le terme mais je ne comprends pas très bien ce qu'il signifie.

Quand dois-je utiliser cette technique et comment l’utiliser ?Quelqu'un peut-il fournir un bon exemple de code ?

Était-ce utile?

La solution

Le modèle de visiteur est une manière d'effectuer une double répartition de manière orientée objet.

C'est utile lorsque vous souhaitez choisir la méthode à utiliser pour un argument donné en fonction de son type au moment de l'exécution plutôt qu'au moment de la compilation.

La double expédition est un cas particulier de expédition multiple.

Lorsque vous appelez une méthode virtuelle sur un objet, cela est considéré comme une répartition unique, car la méthode réelle appelée dépend du type de l'objet unique.

Pour la double répartition, le type de l'objet et le type de l'argument unique de la méthode sont pris en compte.Cela ressemble à la résolution de surcharge de méthode, sauf que le type d'argument est déterminé au moment de l'exécution en double répartition au lieu de statiquement au moment de la compilation.

En répartition multiple, une méthode peut recevoir plusieurs arguments et l'implémentation utilisée dépend du type de chaque argument.L'ordre dans lequel les types sont évalués dépend de la langue.En LISP, il vérifie chaque type du premier au dernier.

Les langages à répartition multiple utilisent des fonctions génériques, qui ne sont que des déclarations de fonctions et ne ressemblent pas à des méthodes génériques, qui utilisent des paramètres de type.

Pour effectuer une double répartition en C#, vous pouvez déclarer une méthode avec un seul argument objet, puis des méthodes spécifiques avec des types spécifiques :

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

Autres conseils

Eh bien, les gars, le code publié par Mark n'est pas complet et tout ce qu'il contient ne fonctionne pas.

Tellement peaufiné et complet.

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

Merci Mark et les autres pour la belle explication sur le modèle Double Dispatcher

C# 4 introduit le pseudo-type dynamic qui résout l'appel de fonction au moment de l'exécution (au lieu de la compilation).(C'est-à-dire que le type d'exécution de l'expression est utilisé).La double (ou la multi-expédition) peut être simplifiée en :

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"
}

Notez également en utilisant dynamic vous empêchez l'analyseur statique du compilateur d'examiner cette partie du code.Vous devez donc soigneusement réfléchir à l'utilisation de dynamic.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top