Двойная диспетчеризация в C#?
Я слышал/читал но не совсем понял что это значит.
когда я должен использовать эту технику и как я буду ее использовать? Может кто-нибудь дать пример кода?
4 ответов
шаблон посетителя-это способ выполнения двойной отправки объектно-ориентированным способом.
это полезно, когда вы хотите выбрать, какой метод использовать для данного аргумента на основе его типа во время выполнения, а не во время компиляции.
двойная отправка является частным случаем множественная диспетчеризация.
когда вы вызываете виртуальный метод на объекте, это считается одинарной отправкой, потому что фактический метод вызывается в зависимости от типа один объект.
для двойной отправки учитывается как тип объекта, так и тип единственного аргумента метода. Это похоже на разрешение перегрузки метода, за исключением того, что тип аргумента определяется во время выполнения в double-dispatch вместо статически во время компиляции.
в multiple-dispatch метод может иметь несколько аргументов, переданных ему, и какая реализация используется, зависит от типа каждого аргумента. Порядок оценки типов зависит от язык. В LISP он проверяет каждый тип от первого до последнего.
языки с множественной отправкой используют общие функции, которые являются просто функциями delcarations и не похожи на общие методы, которые используют параметры типа.
для двойной отправки в 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).
}
}
ну эй, ребята, код, размещенный Марком, не завершен, и что когда-либо там не работает.
так подправлено и завершено.
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();
}
}
спасибо Марк и другие за хорошее объяснение на двойной шаблон диспетчера
Double-dispatch-это другое название для шаблон Visitor.
У меня есть статья, которую я писал несколько лет назад об использовании отражения для реализации шаблона Visitor. http://www.agileprogrammer.com/dotnetguy/articles/ReflectionVisitor.aspx
C# 4 вводит псевдо-тип dynamic
разрешающего вызова функции во время выполнения (а не компиляции). (То есть используется тип времени выполнения выражения). Double-(или multi-dispatch) можно упростить до:
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
.