回答
訪問者模式是一種以面向對象的方式進行雙重調度的方式。
當您想根據運行時的類型而不是編譯時選擇給定參數使用哪種方法時,它非常有用。
雙派遣是多派遣的特例。
當你在一個對象上調用一個虛擬方法時,這被認爲是單調度的,因爲調用的實際方法取決於單個對象的類型。
對於雙重調度,對象的類型和方法唯一參數的類型都被考慮在內。這就像方法重載解析一樣,除了參數類型是在運行時以雙分派而不是在編譯時靜態確定的。
在多次調度中,一個方法可以有多個參數傳遞給它,並且使用哪個實現取決於每個參數的類型。類型的評估順序取決於語言。在LISP中,它從頭到尾檢查每種類型。
具有多次調度的語言使用泛型函數,這些泛型函數只是函數定義,並不像使用類型參數的泛型方法。
要做到在C#雙調度,你可以聲明的方法與鞋底對象意見,並與特定類型的再具體方法:
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).
}
}
Double-dispatch是Visitor pattern的另一個名稱。
我有一篇文章是我幾年前寫的關於使用Reflection來實現訪問者模式的。 http://www.agileprogrammer.com/dotnetguy/articles/ReflectionVisitor.aspx
鏈接似乎已損壞。你能修好它嗎? – Vertexwahn 2013-01-28 09:21:27
嘿傢伙,張貼標記碼心不是完整還有什麼沒有工作。
所以調整和完成。
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();
}
}
感謝Mark和他人很好解釋雙分派器圖案
C#4引入僞類型dynamic
它解決在運行時(而不是編譯時間)的函數調用。 (也就是說,使用表達式的運行時類型)。雙(多分派)可以簡化爲:
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"
}
不過要小心整數類型。由於dynamic
被視爲System.Object
,因此在上例中永遠不會調用void Foo(int x)
。
還要注意,通過使用dynamic
可以防止編譯器使用靜態分析器來檢查這部分代碼。您應該仔細考慮使用dynamic
。
- 1. C++中的雙調度/多方法
- 2. 通過C#中的「動態過載」進行單/雙重調度
- 3. Java方法重載+雙重調度
- 4. 精度雙Objective-C中的
- 5. C++使用鏡像層次結構進行雙重調度
- 6. Java和C++中的雙重調度和訪問者模式的區別
- 7. C++中的雙重排序
- 8. 在C#中實現一個雙重調度功能和對象的擴展
- 9. 在C++中實現具有兩個類層次結構的雙重調度
- 10. C#高雙精度
- 11. c中的浮點數和雙精度#
- 12. Objective-C的stringValue的雙重
- 13. C#雙重標準?
- 14. 雙重分割C
- 15. C翻譯的雙重
- 16. 設置精度爲雙重
- 17. 在C中將雙色調TIFF轉換爲雙色調PNG
- 18. C++代碼中的雙重否定
- 19. 爲什麼不是Java雙重調度造成的死循環?
- 20. C++中的事件調度
- 21. C#,重寫的OnPaint:Alpha透明度與雙緩衝器
- 22. C中無符號雙精度?
- 23. 在C++中減少雙精度範圍
- 24. 雙重調頁定義
- 25. C++使用長雙精度使用雙精度
- 26. 對模塊角度的雙重注入
- 27. C++雙重代表ASM
- 28. 什麼是雙重? (C#)
- 29. Objective-C雙重長計算
- 30. C++雙重分派問題
目前這是做到這一點的最佳方式:https://blogs.msdn.microsoft.com/curth/2008/11/15/c-dynamic-and-multiple-dispatch/ – 2016-10-11 23:20:05
[應用對象組合構建豐富的域模型](https://vimeo.com/195774910)。 – jsuddsjr 2016-12-16 19:06:27
[小心雙重派遣](https://lostechies.com/derekgreer/2010/04/19/double-dispatch-is-a-code-smell/)。可能你可以避免它,以更好的代碼維護。 – 2017-01-19 15:40:02