鉴于:
class BaseClass
{
public virtual void M(int x)
{
}
}
class Derived : BaseClass
{
public override void M(int x)
{
base.M(x);
}
static void M(object x)
{
}
static void Main()
{
var d = new Derived();
d.M(0);
}
}
Run Code Online (Sandbox Code Playgroud)
错误:
无法使用实例引用访问成员'Derived.M(object)'; 用类型名称来限定它
查看C#4.0规范部分7.4(成员查找),第一个要点是:
在类型T中使用K类型参数的名称N的成员查找按如下方式处理:
[...]包含覆盖修饰符的成员将从名为N的可访问成员集中排除
由此我得出结论,Derived.M无法再访问覆盖.相反,编译器必须引用BaseClass.M.
但是,这并不能解释为什么添加静态Derived.M突然导致编译错误.编译器现在只能看到静态成员 Derived.M并断定该成员是无效调用.如果我删除静态,Derived.M那么编译成功.
为什么会这样?
以下步骤似乎发生,并且是编译器错误的原因:
M被删除,只留下编译器的静态版本.静态参数类型object是兼容的int.方法名称也匹配.我真的不能引用规范证明这一点的一个简单的句子,但也§7.4(会员查询),也不3.5节(前往的交通)谈论static与实例,所以我认为这其实根本就没有考虑到所有在做的时候成员查找.
§7.4中的相关部分似乎是:
在类型T中使用K类型参数的名称N的成员查找按如下方式处理:
- 首先,确定一组名为N的可访问成员:
[...]
该集由T中名为N的所有可访问(§3.5)成员组成,包括继承成员和对象中名为N的可访问成员.如果T是构造类型,则通过替换类型参数来获得成员集,如第10.3.2节中所述.包含覆盖修饰符的成员将从集合中排除.
我理解这一部分的方式如上所述:它将返回实例方法和静态方法,然后将删除实例一,因为它具有override修饰符.
此时只剩下静态方法.
它结束了:
最后,[...]确定查找的结果:
如果集合只包含方法,那么这组方法就是查找的结果.
因此,结果是静态方法.
显然,这个问题只发生在你有一个类层次结构的情况下,其中一个派生类声明了一个具有相同名称和兼容参数的静态方法.
将这样的静态方法添加到现有类是简单地向类添加内容仍然是一个重大变化的情况.
虽然我很确定你知道如何解决编译器错误,但我仍然会说出来,得到一个完整的答案:
使用任何基类作为变量的编译时类型.运行时类型仍然可以是派生类型,这不是问题:
BaseClass d = new Derived();
// ^ ^
// compile time type runtime type
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
250 次 |
| 最近记录: |