来自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";
问题:继承是否会错误地抑制此错误?
答案 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
上述解析规则的直观效果如下:要找到由方法调用调用的特定方法,请从方法调用指示的类型开始,然后继续继承链,直到至少一个适用的,可访问的,找到非重写方法声明。然后对在该类型中声明的适用的,可访问的,非重写方法集执行重载解析,并调用由此选择的方法。