Doppia spedizione in C #?

Ho sentito / letto il termine ma non capisco cosa significhi.

Quando dovrei usare questa tecnica e come la userei? Qualcuno può fornire un buon esempio di codice?

Il pattern visitor è un modo di fare double-dispatch in modo orientato agli oggetti.

È utile quando si desidera scegliere quale metodo utilizzare per un determinato argomento in base al suo tipo in fase di esecuzione anziché in fase di compilazione.

La doppia spedizione è un caso speciale di spedizione multipla .

Quando si chiama un metodo virtuale su un object, viene considerato un invio singolo poiché il metodo effettivo viene chiamato in base al tipo del singolo object.

Per la doppia spedizione, vengono presi in considerazione sia il tipo dell’object che il tipo del solo argomento del metodo. Questo è come la risoluzione del sovraccarico del metodo, tranne per il fatto che il tipo di argomento è determinato in fase di runtime in doppio invio invece che staticamente in fase di compilazione.

Nel dispatch multiplo, un metodo può avere più argomenti passati e l’implementazione utilizzata dipende dal tipo di ciascun argomento. L’ordine di valutazione dei tipi dipende dalla lingua. In LISP, controlla ogni tipo dal primo all’ultimo.

Le lingue con dispatch multipli fanno uso di funzioni generiche, che sono solo funzioni di delcaring e non sono come metodi generici, che usano parametri di tipo.

Per eseguire il doppio invio in C # , puoi dichiarare un metodo con un solo argomento object e poi metodi specifici con tipi specifici:

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

Beh, ehi ragazzi, il codice pubblicato da Mark non è completo e quello che è sempre non funziona.

Così ottimizzato e completo.

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

Grazie Marco e altri per una bella spiegazione sul modello di Double Dispatcher

Il doppio invio è un altro nome per il pattern Visitor .

Ho un articolo che ho scritto alcuni anni fa sull’uso di Reflection per implementare il pattern Visitor. http://www.agileprogrammer.com/dotnetguy/articles/ReflectionVisitor.aspx

C # 4 introduce la dynamic pseudo tipo che risolve la chiamata di funzione in fase di esecuzione (invece del tempo di compilazione). (Ovvero, viene utilizzato il tipo di runtime dell’espressione). Double- (o multi-dispatch) può essere semplificato per:

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

Fai attenzione però con i tipi interi. Dato che la dynamic è considerata System.Object , non chiamerà mai void Foo(int x) nell’esempio sopra.

Si noti inoltre che, utilizzando la dynamic si impedisce al compilatore di effettuare analisi statiche su questa parte del codice. Dovresti considerare attentamente l’uso dynamic .