2012-01-29 56 views
2

在C#中,嵌套类可以访问包含类的私有成员。为什么我无法重写嵌套类中的私有成员?

为什么我不能重写这些成员?为什么编译器错误?

private abstract class InheritanceTest 
    { 
     public virtual object Property 
     { 
      get { return null; } 
      private set { } 
     } 

     public class Child : InheritanceTest 
     { 
      public override object Property 
      { 
       get { return null; } 
       private set { base.Property = null; } // the base.Property = null statement here is just to show that there isn't an error message for accesing a parent private member. 
      } 
     } 
    } 

唯一的错误消息我得到的是:

'Program.InheritanceTest.Child.Property.set':不能覆盖继承成员 'Program.InheritanceTest.Property.set',因为它不是标记为虚拟,抽象或覆盖

编译器明显出错,因为整个属性被标记为虚拟。 get方法可以覆盖继承的成员。

这是C#规范的一部分,只有错误消息是错误的?或者应该允许吗?

我错过了什么规范? (或者是编译器不见了?)

+1

的可能重复[为什么在C#中的非法私人虚拟方法?(http://stackoverflow.com/questions/3082310/why-are-private-virtual-方法非法在C) – McKay 2012-01-29 05:43:23

+0

我已投票结束这个问题作为重复。我会鼓励其他人也这样做。 – McKay 2012-07-17 20:31:14

回答

3

有没有这样的事情virtual private。因此,由外部类定义的set访问者不是virtual,因此您无法覆盖它。

对于方法中,所述说明书明确禁止private virtual(该C#4规范的第10.6节):

如果声明包括private改性剂,则声明不包含任何以下修饰符:virtualoverrideabstract

至于特性(第10.7节):

属性声明都受到相同的规则方法声明(第10.6节)中有关改性剂的有效组合。

说明书的唯一部分,这似乎是有关virtual属性,其中所述存取器中的一个是private是(§10.7.5):

virtual属性声明指定了存取器该属性是虚拟的。 virtual修饰符适用于读写属性的两个访问器 - 读写属性只有一个访问者不可能是虚拟的。

这似乎与实际发生的情况相矛盾:只有非private访问器变为虚拟。除非我错过了一些东西,否则我认为这是文档或编译器中的错误。我已经创建了一个关于这个的Connect bug,让我们看看微软有什么要说的。

有关private virtual方法的更多信息,请参阅this answer from Eric Lippert

+0

+1对规范的引用,但我认为这一行文档是正确的。 '虚拟'省略的地方在非读写属性的情况下(不管是只读的还是只写的,其只有1个虚拟成员)。请记住,如果get或set被标记为'private',那么它不再是'virtual',并且属性不再是“读写”,因此不符合该规范的那一行。 – CodingWithSpike 2012-01-29 15:51:20

+0

仅仅因为其中一个访问器具有不同的可访问性,并不意味着该属性不再是可读写的。或者至少我没有在规范中找到任何可以这样说的东西。 – svick 2012-01-29 20:48:16

+0

啊,是的,我明白你的意思,对不起,我从派生类的角度思考“只读”和“只写”,而不是基类本身。抱歉。在那种情况下,是的,我认为你的观点是错的。 – CodingWithSpike 2012-01-30 01:46:44

1

顾名思义,private成员不可覆盖。 如果您希望setter被覆盖,您可以将其标记为protected而不是private

private abstract class InheritanceTest 
    { 
     public virtual object Property 
     { 
      get { return null; } 
      protected set { } 
     } 

     public class Child : InheritanceTest 
     { 
      public override object Property 
      { 
       get { return null; } 
       protected set { base.Property = null; } 
      } 
     } 
    } 

为了更具体地回答你的问题,以为什么

理解的是,当你的C#代码被编译成IL代码,实际上最终是三样东西1财产。

  1. Property属性本身。
  2. 名为get_Property()的方法是吸气剂。
  3. 方法名称set_Property()这是设置者。

在你的代码,你告诉.NET说:“我希望有一个virtual的属性,它然后访问级别的getter和setter方法级联。事实上,在IL代码,性能不指定virtual在所有。

对于C#代码:

public virtual object Property { get; set; } 

所生成的IL代码是:

.property instance object Property() { ... } 

.method public hidebysig newslot specialname virtual 
    instance object get_Property() cil managed 
    { ... } 

.method public hidebysig newslot specialname virtual 
    instance object set_Property() cil managed 
    { ... } 

请注意,publicvirtual关键字既适用于getter方法,也适用于setter方法,但不适用于属性本身。

现在,通过改变你的C#代码:您希望您的getter和setter方法是虚拟

public virtual object Property { get; private set; } 

你告诉.NET ...但是,然后将它运行到private set,和访问级别覆盖publicvirtual访问级别,用于setter方法。因此,生成的IL代码变为:

.property instance object Property() { ... } 

.method public hidebysig newslot specialname virtual 
    instance object get_Property() cil managed 
    { ... } 

.method private hidebysig newslot specialname 
    instance object set_Property() cil managed 
    { ... } 

注意,现在set_Property()private,并且不再virtual。在.NET中实际上不可能有一个private virtual,因为它没有意义......这就像试图说“没有其他类可以看到这个......但派生类可以重写这个东西,他们可以'没有看到或访问“这是没有意义的。派生类不能覆盖他们甚至看不到的东西。

protected关键字在这种情况下是正确的替代品,因为它告诉.NET“只有我自己和派生类可以看到或访问它,并且派生类可以覆盖此属性。”

所以我猜这个“短”的答案会刚刚“因为事情不能在.NET privatevirtual,所以编译器需要你给它的更严格的访问级别。

而且, IMO该错误消息是相当正确

“Program.InheritanceTest.Child.Property.set”:无法重写继承的成员“Program.InheritanceTest.Property.set”,因为它未标记虚拟的,抽象的,或覆盖

请注意,它说的是'Program.InheritanceTest.Property.set',所以最后的“.set”是指最终的set_Property()方法,而不是Property属性。并且set_Property()方法仅标记为private,因为.NET编译器看到该方法,并从该方法中删除了virtual,原因如上所述。我想假设有一个编译器警告或者说'虚拟'将被忽略'set''会有些意义。

希望更有意义......

+0

是的,我已经这样做了,真正的问题是“为什么我必须?”和“为什么错误信息不太有用?” – McKay 2012-01-29 05:41:53

+0

@McKay - 我扩大了我的答案,试图解释“为什么”。 – CodingWithSpike 2012-01-29 15:48:11

相关问题