0

Overriding get-only property with settable property is prohibited in C#.

public class Example : IExample //// OR ExampleBase
{
    public int Property { get; set; } //// This causes error.
}

public abstract class ExampleBase
{
    public abstract int Property { get; }
}

I've already checked question 1 and question 2.

I know how to avoid the error, but I don't know why this should be prohibited.

Please let me know why overriding get-only property with settable property is wrong.

terborac
  • 323
  • 2
  • 13
  • 1
    You seem to be adding "public abstract" to an interface, which won't work. In your `Example` class, you're not overriding anything (there's no `override` keyword). Also note that `{ get; }` isn't equivalent to `{ get; private set; }`, it would be equivalent to `{ get; readonly set; }` (`readonly set` doesn't exist, but it's to demonstrate its equivalency to the `readonly` keyword for fields). – ProgrammingLlama Dec 04 '18 at 08:26
  • 3
    The interface version should work if you make the interface actually compilable. (In fact, I just tried it without `public abstract` in the interface and it does indeed compile) – Damien_The_Unbeliever Dec 04 '18 at 08:30

3 Answers3

3

TL;DR;

Overriding or implementing get-only property with settable property is prohibited in C#.

Partially correct. It's perfectly valid to implement a get-only property with a settable property - but it's invalid to override a get-only property with a settable property.

The long version:

When I've tried to compile your code, I've got two compilation errors (In VS 2017, if that matters)

Error CS0106 The modifier 'abstract' is not valid for this item
Error CS0106 The modifier 'public' is not valid for this item

When removed the public abstract from the property in the interface, the code compiles just fine (removed the abstract class as it's irrelevant here):

public class Example : IExample
{
    public int Property { get; set; } 
}

public interface IExample
{
    int Property { get; }
}

However, when attempting to use an abstract class and override a get only property with a get/set property, I got this compilation error:

Error CS0546 'Example.Property.set': cannot override because 'ExampleBase.Property' does not have an overridable set accessor

for the following code (removed the interface, same error for a private set):

public class Example : ExampleBase
{
    public override int Property { get; set; } 
}

public abstract class ExampleBase
{
    public abstract int Property { get; }
}

This is actually a good way to show the difference between overriding and implementing in c#:

An interface is a contract. It force the implementing types to include it's members as a part of it's public API (explicit implementation aside). So when implementing an interface with a get-only property, you can add a setter to this property, because as long as it has the getter, the contract is still being fulfilled.

However, a base class is not a contract. If forces the inheriting classes to have the exact same member signature, but allows the inheriting class to override virtual members (so the same method or property will be implemented differently in the two classes). In fact, a derived class is a (specific) type of it's base class.

Usually If you want to add a setter to a get-only property in the base class, you will have to shadow it using the keyword new, but this will not help with abstract members - an abstract member must be overriden in the derived class - and since we don't have properties overloads, you will have to add a method to set the value of the get-only property, and implement it explicitly:

public class Example : ExampleBase
{
    private int _property;

    public override int Property { get { return _property; } }

    public void SetProperty(int property)
    {
        _property = property;
    }
}

public abstract class ExampleBase
{
    public abstract int Property { get; }
}

And for the sake of completeness - here is how you would use the new keyword if the base property was not abstract:

public class Example : ExampleBase
{

    public new int Property { get; set; }

}

public class ExampleBase
{
    public virtual int Property { get; }
}
Community
  • 1
  • 1
Zohar Peled
  • 79,642
  • 10
  • 69
  • 121
  • @Zhohar Yes, I could implement IExample. I've edited the question. I'm sorry for making confusion. Now I understand I shouldn't use base classes like contracts. Thank you! – terborac Dec 05 '18 at 08:51
  • I'm glad to help! Please note that I think in the process of editing the question you kind of invalidated the answers. – Zohar Peled Dec 05 '18 at 09:06
1

The abstract and public modifiers are not available in an interface.

Assuming you meant the following:

public class Example : ExampleBase
{
    public override int Property { get; set; } //// This causes error.
    //// public int Property { get; private set; } //// This causes error, too.
}

public interface IExample
{
    int Property { get; }
}

public abstract class ExampleBase
{
    public abstract int Property { get; }
}

When you implement an interface (IExample) you can add a setter. When you extend the abstract class (ExampleBase) you have to implement the property the way the abstract base specifies it must be implemented, that is with just a getter.

ikkentim
  • 1,639
  • 15
  • 30
0

I can't speak in place of the C# language team but to me I think it comes to consistency and avoiding design mistake.

While the CLR doesn't forbid it - you could think a property as a pair of GetProperty() and SetProperty() methods, for which one could be defined in the base class and the other in a derived class - when bundled into a property you are basically expressing a contract to access a "resource" (usually a field).

So when the base class declares a property to be getter only, you don't expect concrete implementation to expose a setter in the same place. If the concrete class does need to so, then it better conveys its intent by defining a separate method, since it is kind of "breaking" the class contract.

When it comes to interface, on the other hand, the contract is only on a "surface" API: just just say that method or that getter must be implemented. And you could have one interface defining get-only properties and one interface defining set-only properties (why not).

Kryptos
  • 875
  • 8
  • 19