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]);
    }
}