通过C#中的“动态过载”进行单/双调度

时间:2014-10-01 20:12:19

标签: c# .net parametric-polymorphism

为什么要通过"动态过载"进行双重调度?基于参数类型是不是由C#原生支持?我发现这需要动态调度,但由于虚拟方法调用也是动态调度的,因此对语言来说并不奇怪。那么为什么这个功能不属于C#呢?使用Reflection实现此功能的最优雅的解决方案是什么(可能有一些库)?

class Program
{
    static void Main(string[] args)
    {
        var objs = new object[] { new Class1(), new Class2() };
        foreach (var item in objs)
        {
            Method(item);
        }
    }

    static void Method(Class1 obj)
    {
    }

    static void Method(Class2 obj)
    {
    }
}

class Class1
{
}

class Class2
{
}

更新确实,因为此示例中的Method不是虚拟的并且只接受一个参数,所以这仍然是单个调度但是"基数"发送的问题在这个问题中并不重要,只要它是> 0

3 个答案:

答案 0 :(得分:10)

virtual用于单次发送。如果您需要双重发送,可以在C#中执行此操作:

var objs = new object[] { new Class1(), new Class2() };
foreach (var item in objs)
{
    Method((dynamic)item);
}

这将使编译器以非常不同的方式解释对方法的调用。它将发出一个所谓的调用站点,它将在运行时确定应该调用哪个方法。这也称为后期绑定

在这个具体示例中,您仍然可以获得单个调度,但如果Method是虚拟的,那么它将是双重调度。

这对于快速实现访问者模式非常方便,但请注意,这将比传统的手动双重调度慢。因此,您可能希望在性能敏感的代码中使用旧的方法。

答案 1 :(得分:4)

  

为什么要通过"动态过载"进行双重调度?基于参数类型是否由C#本身支持?

通过dynamic typing

static void Main(string[] args)
{
    var objs = new object[] { new Class1(), new Class2() };
    // Note the change of type for item to "dynamic"
    foreach (dynamic item in objs)
    {
        Method(item);
    }
}

涉及编译时类型为dynamic的值的操作是后期绑定的 - 因此,在执行时根据值的实际类型执行重载解析。除了重载解析之外,动态类型还有很多,当然,包括能够通过代码动态提供成员的类型。

所有这些都有性能影响 - 但有时它是最干净的方法。

您可能希望使用object类型的参数添加额外的重载作为" catch-all"如果一个值与其他任何重载都没有匹配......虽然如果你的数组包含一个null元素,它仍然是不明确的。

答案 2 :(得分:3)

如果你真的感兴趣的话,.Net CLR仿制药的设计者之一Andrew Kennedy写了一篇关于此的文章。

http://research.microsoft.com/pubs/64039/transposingftocsharp.pdf

由于具有真正参数化多态性的F#使用相同的公共语言运行时,可能C#也可以实现它,并且决定是保留C ++ / C#语言风格。

从他的文章:"同样,多态虚拟方法[10]的CLR实现涉及执行时代码生成,与足以支持非虚拟多态方法的加载时代码生成形成对比。 #34;