【问题标题】:Double dispatch in C# 4.0 - dynamic keyword?C# 4.0 中的双重调度 - 动态关键字?
【发布时间】:2012-03-22 18:04:06
【问题描述】:

我知道以前有人问过这个问题,但我没有就最佳解决方案达成明确的一致意见。

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

(classA1 和 classA2 实现接口 A,B 也一样)

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

static void Foo(classA1 a, classB1 b) {  //some code }
static void Foo(classA2 a, classB2 b) {  //some code }
static void Foo(classA1 a, classB2 b) {  //some code }
static void Foo(classA2 a, classB1 b) {  //some code }

或者类似的......

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

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

【问题讨论】:

  • 您可以通过在其中一个类上使用标准动态调度来删除(dynamic) 强制转换之一(即调用为a.Foo(Interface B))。之后,您可以使用dynamic(在这里可以使用)或实现访问者模式。
  • 你想用这个模式做什么?我认为有更好的模式可以解决你的问题然后使用动态。您是否测试过代码是否以这种方式工作?

标签: c# dynamic overloading


【解决方案1】:

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

嗯,这是一种的方法——只要执行时类型总是以重载决议会满意的东西结束。

你可能想放一个支持方法

static void Foo(object x, object y)

如果这些方法都不适用(例如,a 是非 ClassA1/ClassA2 实现)。如果两个值都为空,这对您没有帮助,请注意...

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

【讨论】:

  • 我相信在这种情况下重载类型总是正确的。我只是在几个地方读到了动态,使用访问者模式可能不再需要双重调度了。
  • 上下文是我的 Foo 是交叉点,我的类是各种几何对象。不确定这是否有帮助。如果当前的智慧是坚持传统的访客模式,我很乐意重新设计。
【解决方案2】:

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

static void Foo(InterfaceA a, InterfaceB b) {
    classA1 c1 = a as classA1;
    classB1 b1 = b as classB1;
    // ... etc
}

Dynamic 不适合以这种方式使用。

【讨论】:

  • 意图是调用“重载”Foo 接受类类型参数取决于 a 和 b 的底层类型
【解决方案3】:

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

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

【讨论】:

    【解决方案4】:

    C# 传统上是一种静态类型的语言。动态关键字adds dynamic typing to the language。通常的建议是使用“动态”sparingly。这里可能是您需要它的情况。

    Generics 不会删掉它,因为这不会编译:

        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 { }
    

    【讨论】:

    • 除非涉及动态,否则在编译时完成重载解析,因此这种方法行不通。
    • 确实,我的意思是泛型不起作用,所以他可能没有太多选择,只能使用动力学。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-08
    • 2010-10-01
    • 2011-01-19
    • 2010-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多