6

为什么 C# 本身不支持通过基于参数类型的“动态重载”进行双重分派?我看到这需要动态调度,但由于虚拟方法调用也是动态调度的,这对语言来说并不奇怪。那么为什么这个特性不是 C# 的一部分呢?使用反射实现此功能的最优雅的解决方案是什么(也许有一些库)?

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。

4

3 回答 3

10

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

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

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

Method在这个特定的示例中,您仍然会获得单次调度,但如果是虚拟的,它将是双重调度。

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

于 2014-10-01T20:14:15.987 回答
4

为什么 C# 本身不支持通过基于参数类型的“动态重载”进行双重分派?

它是,通过动态类型

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如果一个值与其他任何一个重载都不匹配,您可能希望添加一个带有类型参数的额外重载作为“包罗万象”...尽管如果您的数组包含空元素,它仍然会模棱两可。

于 2014-10-01T20:17:28.410 回答
3

如果您真的感兴趣,.Net CLR 泛型的设计者之一 Andrew Kennedy 写了一篇关于此的文章。

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

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

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

于 2014-10-01T20:38:49.067 回答