代码之家  ›  专栏  ›  技术社区  ›  andreialecu

通用过载分辨率

  •  7
  • andreialecu  · 技术社区  · 14 年前

    class Foo { }
    
    class Foo<T> : Foo { }
    

    然后是两种方法

    void DoStuff(Foo foo) 
    {
         DoStuffImpl(foo);
    }
    
    void DoStuffImpl(Foo foo) 
    { 
         Console.WriteLine("A");
    }    
    void DoStuffImpl<T>(Foo<T> foo) 
    { 
         Console.WriteLine("B");
    } 
    
    void Main() 
    {
         DoStuff(new Foo<int>()); // prints A
    }
    

    (注意,代码是在浏览器中编写的,但描述了我面临的情况)

    如何让它调用泛型方法并打印B?

    这样做完全可以不经思考吗?我有一些关于如何通过反射来实现的想法,但是如果存在的话,我正在寻找一个更干净的解决方案。

    注意:我做不到 DoStuff 泛型,因为这将与WCF一起使用,不允许使用开放泛型类型。

    2 回复  |  直到 14 年前
        1
  •  18
  •   Jon Skeet    14 年前

    (我想你已经明白为什么会这样了。如果没有,读我的 overload resolution article 如果还不清楚,请告诉我。)

    能够 使用动态键入:

    void DoStuff(Foo foo) 
    {
        dynamic d = foo;
        DoStuffImpl(d);
    }
    

    请注意,这不仅仅是一个动态参数,其思想是通过限制 foo 属于 Foo 或者一个子类,我们将 DoStuffImpl 打电话。。。只是最好的方法将在执行时确定,而不是在编译时确定。

    class Foo
    {
        public virtual void CallStuffImpl(FooImplType x)
        {
            x.DoStuffImpl(this);
        }
    }
    
    class Foo<T> : Foo
    {
        public override void CallStuffImpl(FooImplType x)
        {
            // Looks like it's redundant, but isn't! "this" is
            // known to be Foo<T> rather than Foo
            x.DoStuffImpl(this);
        }
    }
    

    然后:

    void DoStuff(Foo foo) 
    {
        foo.CallStuffImpl(this); // Let it dispatch appropriately
    }
    
        2
  •  17
  •   Eric Lippert    14 年前

    过载解决在 编译时间 . 当“DoStuff”被编译时,它已经决定了调用哪个版本的dostuffinpl,并且它决定基于编译时可用的信息,而不是运行时可用的信息。

    C#中有四种方法调度:

    • 静态调度在编译时选择一个静态方法。在运行时,调用所选的方法。

    • 实例调度在编译时选择一个实例方法。在运行时,调用所选的方法。(这是在非虚拟实例方法和用“base”调用的虚拟方法上使用的分派形式。)

    • 虚拟调度在编译时选择一个实例方法。在运行时 对象的运行时类型上该方法的最重写版本

    • 动态调度在编译时不执行任何操作(*)。运行时 这听起来是非常昂贵的;幸运的是结果被缓存了,这样在第二次调用时,您就不会再次得到所有分析和codegen的开销。

    动态调度仅在C#4或任何版本的VB中可用。