代码之家  ›  专栏  ›  技术社区  ›  Faizan S.

为什么C调用错误的重载?

  •  7
  • Faizan S.  · 技术社区  · 14 年前

    我有下面的代码 材料:

    class Parent {
        public virtual void DoSomething(IEnumerable<string> list) {
            Console.WriteLine("Parent.DoSomething(IEnumerable<string>)");
        }
    }
    
    class Child : Parent {
        public override void DoSomething(IEnumerable<string> list) {
            Console.WriteLine("Child.DoSomething(IEnumerable<string>)");
        }
    
        public void DoSomething(IEnumerable<object> list) {
            Console.WriteLine("Child.DoSomething(IEnumerable<object>)");
        }
    }
    

    如你所见 DoSomething 方法 Child 被正确重写。

    以下代码的输出非常意外:

    ...
    Child c = new Child();
    var list = new List<string> { "Hello", "World!" };
    c.DoSomething(list);
    ...
    

    印刷品 Child.DoSomething(IEnumerable<object>)

    鉴于 Parent 参考文献 c

    ...
    Parent c = new Child();
    var list = new List<string> { "Hello", "World!" };
    c.DoSomething(list);
    ...
    

    印刷品 Child.DoSomething(IEnumerable<string>)

    为什么会这样 ?!

    3 回复  |  直到 14 年前
        1
  •  10
  •   Jon Skeet    14 年前

    发生这种情况是因为C编译器遵守规范:)

    规范指出,如果在派生类型中声明的任何方法都适用,则任何方法 最初申报 在基类中(即使它们在派生类型中被重写)从候选集合中移除。

    现在因为您使用的是C#4(大概),这里有一个隐式转换 List<string> IEnumerable<object> 所以你的 Child.DoSomething(IEnumerable<object>) 重载是适用的,编译器从不真正考虑使用 IEnumerable<string> .

    我有一个 article about overloading 这和其他一些奇怪的事情有关。

    我建议您不要在类型层次结构中重载,这会让人困惑。

        2
  •  0
  •   Floyd user1988754    14 年前

    可能的灵魂,试试:

    class Child : Parent {
        public override void DoSomething(IEnumerable<string> list) {
             Console.WriteLine("Child.DoSomething(IEnumerable<string>)");
        }
    
        public void DoSomething(IEnumerable<object> list) {
            if(list is IEnumerable<string>){
                DoSomething((IEnumerable<string>)list);
                return;
            }
            else  
                Console.WriteLine("Child.DoSomething(IEnumerable<object>)");
        }
    }
    
        3
  •  0
  •   Shiv Kumar    14 年前

    @拉丝,

    你写的

    因为编译器只使用它所知道的对象的类型,而且它只知道对象支持父对象中的内容,因此在解析方法调用时只有一个方法可用。

    关于方法解析规则。它不应该选择更具体的方法吗?我知道这在现阶段还没有定论。在3.5和2中,它将选择更具体的方法。

    推荐文章