Double envoi en C #?

J’ai entendu / lu le terme mais je ne comprends pas tout à fait ce que cela signifie.

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

Le modèle de visiteur est une manière de procéder à une double répartition de manière orientée object.

C’est utile lorsque vous voulez choisir la méthode à utiliser pour un argument donné en fonction de son type à l’exécution plutôt que lors de la compilation.

La double expédition est un cas particulier d’ expédition multiple .

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

Pour la double expédition, le type de l’object et le type d’argument de la méthode sont pris en compte. C’est comme la résolution de surcharge de la méthode, sauf que le type d’argument est déterminé lors de l’exécution dans une double dissortingbution au lieu de statiquement au moment de la compilation.

Dans la 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. Dans 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 delcarations de fonctions et ne sont pas comme des méthodes génériques, qui utilisent des parameters de type.

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

using System.Linq; class DoubleDispatch { public T Foo(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(x); //should call Foo(int) via Foo(object). } } 

Eh bien les gars, le code publié par Mark n’est pas complet et ce qui est toujours là ne fonctionne pas.

Donc peaufiné et complet.

 class DoubleDispatch { public T Foo(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 ssortingng Foo(ssortingng arg) { return 5.ToSsortingng(); } public static void Main(ssortingng[] args) { object x = 5; DoubleDispatch dispatch = new DoubleDispatch(); Console.WriteLine(dispatch.Foo(x)); Console.WriteLine(dispatch.Foo(x.ToSsortingng())); Console.ReadLine(); } } 

Merci Mark et d’autres pour une bonne explication sur le motif Double Dispatcher

La double envoi est un autre nom du motif de visiteur .

J’ai écrit un article il y a quelques années sur l’utilisation de Reflection pour implémenter le motif Visitor. http://www.agileprogrammer.com/dotnetguy/articles/ReflectionVisitor.aspx

C # 4 introduit le pseudo type dynamic qui résout l’appel de la fonction à l’exécution (au lieu de la compilation). (C’est-à-dire que le type d’exécution de l’expression est utilisé). Double (ou multi-dispatch) peut être simplifié pour:

 class C { } static void Foo(C x) => Console.WriteLine(nameof(Foo)); static void Foo(object x) => Console.WriteLine(nameof(Object)); public static void Main(ssortingng[] args) { object x = new C(); Foo((dynamic)x); // prints: "Foo" Foo(x); // prints: "Object" } 

Soyez prudent avec les types intégraux. Puisque la dynamic est traitée comme System.Object elle n’appellera jamais void Foo(int x) dans l’exemple ci-dessus.

Notez également qu’en utilisant dynamic vous empêchez le compilateur et les parsingurs statiques d’examiner cette partie du code. Vous devriez examiner attentivement la dynamic utilisation.