C#4.0中的双重分派-动态关键字?

C#4.0中的双重分派-动态关键字?,c#,dynamic,overloading,C#,Dynamic,Overloading,我意识到以前有人问过这个问题,但我没有找到一个关于最佳解决方案的明确协议 使用动态(如下所示)是最好的方法吗? 我想最好尽可能避免动态,以帮助在编译时捕获问题 (classA1和classA2实现接口A,对于B也是如此) 或者类似地 public static void Foo(InterfaceA a, InterfaceB b) { ((dynamic) a).Foo(b); } public classA1 { void Foo(classB1 b) { /

我意识到以前有人问过这个问题,但我没有找到一个关于最佳解决方案的明确协议

使用动态(如下所示)是最好的方法吗? 我想最好尽可能避免动态,以帮助在编译时捕获问题

(classA1和classA2实现接口A,对于B也是如此)

或者类似地

public static void Foo(InterfaceA a, InterfaceB b) 
 { 
    ((dynamic) a).Foo(b); 
 }

public classA1
{
     void Foo(classB1 b) {  //some code }
}
//repeated for other cases    

“classA1”等是
InterfaceA
的实现吗?如果是这样的话,为什么不将
Foo
函数声明为接受
InterfaceA
InterfaceB
并将它们转换为函数所期望的具体实现呢?例如:

static void Foo(InterfaceA a, InterfaceB b) {
    classA1 c1 = a as classA1;
    classB1 b1 = b as classB1;
    // ... etc
}
Dynamic不打算以这种方式使用

使用动态(如下所示)是最好的方法吗

好吧,这是一种方法——只要执行时间类型总是以重载解析满意的方式结束

你可能想用一种支持方法

static void Foo(object x, object y)
如果这些方法都不适用(例如,
a
是非ClassA1/ClassA2实现)。如果这两个值都为空,它将不会对您有帮助,请注意

我通常会尝试重新设计,这样就不需要了,但是如果没有更多的上下文,就很难知道最好的解决方案。

C#传统上是一种静态类型语言。动态关键字。通常的建议是使用“动态”。这里可能有一个你需要的案例

泛型不会剪切它,因为它不会编译:

    private void button1_Click(object sender, EventArgs e)
    {
        Foo(new classA1(), new classB2());
    }

    static void Foo<T, T1>(T a, T1 b) where T: InterfaceA
        where T1: InterfaceB
    {
        Foo2(a, b);
    }

    static void Foo2(classA1 a, classB1 b) { }
    static void Foo2(classA2 a, classB2 b) { }
    static void Foo2(classA1 a, classB2 b) { }
    static void Foo2(classA2 a, classB1 b) { }

    interface InterfaceA { }
    interface InterfaceB { }

    class classA1 : InterfaceA { }
    class classA2 : InterfaceA { }

    class classB1 : InterfaceB { }
    class classB2 : InterfaceB { }
private void按钮1\u单击(对象发送者,事件参数e)
{
Foo(新类a1(),新类b2());
}
静态空隙Foo(ta,T1 b),其中T:InterfaceA
其中T1:b
{
Foo2(a,b);
}
静态voidfoo2(类a1a,类b1b){}
静态voidfoo2(classa2a,classb2b){}
静态voidfoo2(类a1a,类b2b){}
静态空洞Foo2(类a2 a,类b1 b){}
接口a{}
接口B{}
类1:InterfaceA{}
类别A2:接口A{}
类classB1:接口B{}
类classB2:接口B{}

你可以用反射做一些糟糕的事情,但我相信这并不比使用动态反射更好:

void Main()
{
    var a = "hello";//5;
    var b = "hello"; 

    var type1 = a.GetType();
    var type2 = b.GetType();

    var t = typeof(FooClass);

    var methods = t.GetMethods();

    foreach(var method in methods)
    {
        var parameters = method.GetParameters();

        if(parameters.Length == 2)
        {
            if(parameters[0].ParameterType == type1 
               && parameters[1].ParameterType == type2)
            {
                method.Invoke(this, new object[]{ a, b });
            }
        }
    }
}

public static class FooClass
{
    public static void Foo(int i, string s)
    {
        "Foo1".Dump();
    }

    public static void Foo(string s, string s2)
    {
        "Foo2".Dump();
    }
}

您可以通过在其中一个类上使用标准的动态分派(即调用为
a.Foo(接口B)
),删除其中一个
(动态)
强制转换。在这之后,您可以使用
动态
(在这里可以使用)或实现访问者模式?我认为有更好的模式可以解决您的问题,而不是使用动力学。如果代码是这样工作的,您测试过了吗?其目的是对“重载”Foo接受类类型参数的调用取决于bI的底层类型,并且我相信在这种情况下重载类型将始终是正确的类型。我刚刚在一些地方读到,使用dynamic,双重分派可能不再需要使用访问者模式。上下文是我的Foo是交集,我的类是各种几何对象。我不确定这是否有帮助。如果当前的智慧是坚持传统的访问者模式,我很乐意重新设计。除非涉及动态,否则重载解析是在编译时完成的,所以这种方法不起作用。事实上,我的观点是泛型不起作用,所以他可能没有很多选择,只能使用动态。
void Main()
{
    var a = "hello";//5;
    var b = "hello"; 

    var type1 = a.GetType();
    var type2 = b.GetType();

    var t = typeof(FooClass);

    var methods = t.GetMethods();

    foreach(var method in methods)
    {
        var parameters = method.GetParameters();

        if(parameters.Length == 2)
        {
            if(parameters[0].ParameterType == type1 
               && parameters[1].ParameterType == type2)
            {
                method.Invoke(this, new object[]{ a, b });
            }
        }
    }
}

public static class FooClass
{
    public static void Foo(int i, string s)
    {
        "Foo1".Dump();
    }

    public static void Foo(string s, string s2)
    {
        "Foo2".Dump();
    }
}