C# 为了指定类型参数!!您也可以不必费心处理所有的反射代码,而直接强制转换对象。我遗漏了什么吗?它确实实现了双重分派,因为它同时分派对象的运行时类型(派生自DoubleDispatch)和方法参数。返回类型的反射用于将机制扩展到子类,因此您可以将“string
C# 为了指定类型参数!!您也可以不必费心处理所有的反射代码,而直接强制转换对象。我遗漏了什么吗?它确实实现了双重分派,因为它同时分派对象的运行时类型(派生自DoubleDispatch)和方法参数。返回类型的反射用于将机制扩展到子类,因此您可以将“string,c#,design-patterns,language-features,double-dispatch,C#,Design Patterns,Language Features,Double Dispatch,为了指定类型参数!!您也可以不必费心处理所有的反射代码,而直接强制转换对象。我遗漏了什么吗?它确实实现了双重分派,因为它同时分派对象的运行时类型(派生自DoubleDispatch)和方法参数。返回类型的反射用于将机制扩展到子类,因此您可以将“string Foo(string)”添加到子类中,它将正常工作。鉴于我们现在在C#中有一个动态类型,这里仅用于历史目的。请随意编辑我的答案。如果使用反射来解释双重分派,我认为这个例子不是很好。因为我认为不需要反思。我认为一个例子应该显示出最基本的本质。也
为了指定类型参数!!您也可以不必费心处理所有的反射代码,而直接强制转换对象。我遗漏了什么吗?它确实实现了双重分派,因为它同时分派对象的运行时类型(派生自DoubleDispatch)和方法参数。返回类型的反射用于将机制扩展到子类,因此您可以将“string Foo(string)”添加到子类中,它将正常工作。鉴于我们现在在C#中有一个动态类型,这里仅用于历史目的。请随意编辑我的答案。如果使用反射来解释双重分派,我认为这个例子不是很好。因为我认为不需要反思。我认为一个例子应该显示出最基本的本质。也许我只是看不到双重派遣正在解决的问题。我同意。这段代码是完整的,显示了双重分派的真正含义。马克的回答和这段代码的解释完美地结合在一起。写“Console.WriteLine(dispatch.Foo(x));”不是一种更动态、更有用的方式来利用这个模式吗?目前这是最好的方式:双重分派的一个很好的例子。。为了更好地维护代码,您可能可以避免使用它。
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();
}
}
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"
}
class SpaceShip
{
public virtual void CollideWith(Asteroid asteroid)
{
asteroid.CollideWith(this);
}
}
class ApolloSpacecraft : SpaceShip
{
public override void CollideWith(Asteroid asteroid)
{
asteroid.CollideWith(this);
}
}
class Asteroid
{
public virtual void CollideWith(SpaceShip target)
{
Console.WriteLine("Asteroid hit a SpaceShip");
}
public virtual void CollideWith(ApolloSpacecraft target)
{
Console.WriteLine("Asteroid hit ApolloSpacecraft");
}
}
class ExplodingAsteroid : Asteroid
{
public override void CollideWith(SpaceShip target)
{
Console.WriteLine("ExplodingAsteroid hit a SpaceShip");
}
public override void CollideWith(ApolloSpacecraft target)
{
Console.WriteLine("ExplodingAsteroid hit ApolloSpacecraft");
}
}
class Program
{
static void Main(string[] args)
{
Asteroid[] asteroids = new Asteroid[] { new Asteroid(), new ExplodingAsteroid() };
ApolloSpacecraft spacecraft = new ApolloSpacecraft();
spacecraft.CollideWith(asteroids[0]);
spacecraft.CollideWith(asteroids[1]);
SpaceShip spaceShip = new SpaceShip();
spaceShip.CollideWith(asteroids[0]);
spaceShip.CollideWith(asteroids[1]);
}
}