属性和方法之间的歧义

时间:2016-06-14 07:13:53

标签: c# inheritance

来自here我的代码中有相同的内容。假设我有以下课程:

public class EList<T> : List<T>
{
    public string Add { get; set; }
}

现在我期待错误

  

'EList.Add'和'EList.Add(int)'

之间存在歧义

但以下代码可以正常运行:

EList<int> il = new EList<int>();
il.Add(1);
il.Add = "test";

问题:继承是否会错误地抑制此错误?

3 个答案:

答案 0 :(得分:4)

在C#(C# Specification第7.4节)的成员查找规则中明确地提供了它。具体来说,重要的是 invocability

  

跳过早期规则

     
      
  • 接下来,如果调用该成员,则从该集合中删除所有不可调用的成员。 (调用了对Add()的调用。因此,Add属性已从集合中移除

  •   
  • 接下来,从集合中删除被其他成员隐藏的成员。对于集合中的每个成员S.M,其中S是声明成员M的类型,应用以下规则:

         
        
    • 如果M是常量,字段,属性,事件或枚举成员,则从集合中删除在基本类型S中声明的所有成员。 (基本类型中的Add方法已删除
    •   
  •   
     

更多规则

所以在这一点上,由于上​​述两条规则已经消除了一个或另一个可能存在冲突的成员,因此没有歧义。

另见第10.3节,班级成员:

  

常量,字段,属性,事件或类型的名称必须与相同类中声明的所有其他成员的名称不同。

     

方法的名称必须与相同类中声明的所有其他非方法的名称不同。另外......

我的重点

  

类类型的继承成员(第10.3.3节)不是类的声明空间的一部分。因此,允许派生类声明与继承成员具有相同名称或签名的成员

答案 1 :(得分:2)

您的代码实际上会发出警告:

  

警告CS0108&#39; EList.Add&#39;隐藏继承成员&#39; List.Add(T)&#39;。如果想要隐藏,请使用new关键字。

这里没有含糊之处。 il.Add(1);(因为())是方法调用。因此编译器会查找名为Add的方法。 il.Add = "test";(因为=)是属性设置者调用。因此编译器会查找名为Add的属性。

所以似乎Add属性覆盖Add方法。然后il.Add(1);il.Add = "test";调用选择最佳匹配解决方案。

答案 2 :(得分:2)

这里没有歧义,因为Add属性是在子类中定义的,但Add方法在您的父类中。只有在同一个班级中有相同名字的成员时才会出现歧义。这里创建的对象是EList类型,你用类型为EList的变量引用它,这样编译器就知道在你的父类中定义了一个Add方法。 Add属性也是。

即使您在Add中定义了另一个EList方法,也不会出现任何错误,只是警告您正在隐藏基类中已经实现的成员。

这会提供更详细的信息MSDN

  

上述解析规则的直观效果如下:要找到由方法调用调用的特定方法,请从方法调用指示的类型开始,然后继续继承链,直到至少一个适用的,可访问的,找到非重写方法声明。然后对在该类型中声明的适用的,可访问的,非重写方法集执行重载解析,并调用由此选择的方法。