C#语言规范是否指定使用方法重写还是阴影?

C#语言规范是否指定使用方法重写还是阴影?,c#,programming-languages,specifications,C#,Programming Languages,Specifications,考虑以下源代码: public abstract class SomeBaseClass { public abstract void Foo(object a); } public class SomeClass<T> : SomeBaseClass { public override void Foo(object a) { Console.WriteLine("Foo() from SomeBaseClass"); }

考虑以下源代码:

public abstract class SomeBaseClass {

    public abstract void Foo(object a);

}

public class SomeClass<T> : SomeBaseClass {

    public override void Foo(object a) {
        Console.WriteLine("Foo() from SomeBaseClass");
    }

    public void Foo(T a) {
        Console.WriteLine("Foo() from SomeClass");
    }

}
C#语言规范是否说明了以下以某种方式编译的示例中的预期行为

public class Baz : SomeClass<object> { }

var baz = new Baz();
baz.Foo(null); // "Foo() from SomeClass"
公共类Baz:SomeClass{}
var baz=新的baz();
baz.Foo(空);//“来自某个类的Foo()”
检查此项

继承可能会造成混乱的效果。当编译器查找实例方法重载时,它会考虑调用的“目标”的编译时类,并查看其中声明的方法。如果它找不到任何合适的,那么它会查看父类。。。然后是祖父母类,等等。这意味着如果在层次结构的不同级别上有两个方法,那么将首先选择“更深层次”的方法,即使它不是调用的“更好的函数成员”。下面是一个相当简单的例子:

using System;

class Parent
{
    public void Foo(int x)
    {
        Console.WriteLine("Parent.Foo(int x)");
    }   
}

class Child : Parent
{
    public void Foo(double y)
    {
        Console.WriteLine("Child.Foo(double y)");
    }
}


class Test
{
    static void Main()
    {
        Child c = new Child();
        c.Foo(10);
    }
}
方法调用的目标是Child类型的表达式,因此编译器首先查看子类。这里只有一个方法,并且它是适用的(有一个从int到double的隐式转换),所以这就是被选中的方法。编译器根本不考虑父方法。

这样做的原因是为了降低脆弱基类问题的风险,在这种情况下,向基类引入新方法可能会给从基类派生的类的使用者带来问题

但这种行为有一个方面特别令人惊讶。在类中被“声明”的方法算什么?事实证明,如果重写子类中的基类方法,则不算声明它。让我们稍微调整一下示例:

using System;

class Parent
{
    public virtual void Foo(int x)
    {
        Console.WriteLine("Parent.Foo(int x)");
    }   
}

class Child : Parent
{
    public override void Foo(int x)
    {
        Console.WriteLine("Child.Foo(int x)");
    }   

    public void Foo(double y)
    {
        Console.WriteLine("Child.Foo(double y)");
    }
}


class Test
{
    static void Main()
    {
        Child c = new Child();
        c.Foo(10);
    }
}
在我看来,现在您似乎试图调用Child.Foo(intx)——但上面的代码实际上会打印Child.Foo(双y)。编译器忽略子对象中的重写方法

考虑到这种奇怪的情况,我的建议是避免跨越继承边界重载。


首先,T中声明的名为N的所有可访问成员集(第3.5节)和基类型(第7.3.1节)包含重写修饰符的声明将从集合中排除。如果名为N的成员不存在且不可访问,则查找将不产生匹配,并且不会计算以下步骤。“

检查此项:@jonsket-您可以在这方面提供更多帮助。.好的,因此集合将包含
SomeClass.Foo(T)
SomeBaseClass.Foo(对象)
。这是如何回答这个问题的?@svick“所有在基类型S中声明的签名与M相同的方法都将从集合中删除。”
using System;

class Parent
{
    public virtual void Foo(int x)
    {
        Console.WriteLine("Parent.Foo(int x)");
    }   
}

class Child : Parent
{
    public override void Foo(int x)
    {
        Console.WriteLine("Child.Foo(int x)");
    }   

    public void Foo(double y)
    {
        Console.WriteLine("Child.Foo(double y)");
    }
}


class Test
{
    static void Main()
    {
        Child c = new Child();
        c.Foo(10);
    }
}