By definition, private members are not overridable. If you want the setter to be overridable, you can mark it protected instead of 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; } } } }
To more specifically answer your question as to why:
Understand that when your C# code is compiled to IL code, there actually ends up being 3 things for 1 property.
- The
Property property itself. - A method named
get_Property() which is the getter. - A method names
set_Property() which is the setter.
In your code, you have told .NET that "I want a virtual property. It then cascades that access level to the getter and setter methods. Actually, in IL code, properties don't specify virtual at all.
For the C# code:
public virtual object Property { get; set; }
The generated IL code is:
.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 { ... }
Note that the public and virtual keywords are applied to both the getter and the setter methods, but not the property itself.
Now, by changing your C# code to:
public virtual object Property { get; private set; }
You have told .NET that you want your getter and setter methods to be virtual... however, then it runs into private set, and that access level overrides the public and virtual access level, for the setter method. So, the generated IL code becomes:
.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 { ... }
Note that now set_Property() is private, and no longer virtual. It is actually impossible to have a private virtual in .NET, because it doesn't make sense... that is like trying to say "no other class can see this... but derived classes can override this thing, which they can't see or access" which doesn't make sense. Derived classes can't override what they can't even see.
The protected keyword is the proper replacement in this case, because it tells .NET "Only myself and derived classes can see or access this, and derived classes can override this property."
So I guess the "short" answer would have just been "because things can't be private and virtual in .NET, so the compiler takes the more restricted access level that you gave it.
Also, IMO the error message is pretty correct.
'Program.InheritanceTest.Child.Property.set': cannot override inherited member 'Program.InheritanceTest.Property.set' because it is not marked virtual, abstract, or override
Note that it is saying 'Program.InheritanceTest.Property.set' so the ".set" at the end is referring to the eventual set_Property() method, not the Property property. And the set_Property() method is marked private only, because the .NET compiler saw that, and removed virtual from that method, for the reason mentioned above. I suppose it would make some sense to have a compiler warning or something saying that "virtual will be ignored for 'set'".
Hopefully that makes more sense...