Initial conditions:

interface ISomeInterface { int SomeProperty { get; } } abstract class SomeClass { public abstract int AnotherProperty { get; } } class InheritedClass : SomeClass, ISomeInterface { public int SomeProperty { get; set; } public override int AnotherProperty { get; set; }//Ошибка } 

Why does an error occur when implementing an abstract property in a descendant class, if you add a getter or setter that is not declared in the abstract property? And why there is no error for the property declared in the interface under the same conditions?

    1 answer 1

    In terms of interfaces, everything is correct. A property is a pair of methods. In the interface, we require a class that implements our interface to implement a property with the specified accessor, while not imposing any conditions on the presence or absence of the second accessor.

    With the abstract class is a bit more complicated. When implementing an abstract property, we must specify the override keyword, indicating the compiler, that the property was declared in the base class, before such a property.

    The syntax does not allow you to specify override for one particular accessor, but only for the entire property as a whole, therefore an accessor undeclared in the base class also receives an override label, but it cannot be overridden because it is not in the base class.

    Thus, we have a contradiction: on the one hand, we are trying to add a heir to the class, which should not cause any problems, but on the other hand, following the syntax of the language, we are trying to redefine the nonexistent method, which quite naturally causes a compilation error.

    The question of why it was done this way, I’ll leave the language specifications to the developers, in any case it’s unlikely that they will fix it in the near future, if they correct it at all, so it’s easier to take it as a “feature” of the language and just know about it.

    How to work around a problem

    One of the possible solutions to circumvent this "feature":

     abstract class SomeClass { public int AnotherProperty { get { return GetAnotherProperty(); } } protected abstract int GetAnotherProperty(); } class InheritedClass : SomeClass { public new int AnotherProperty { get; set; } protected override int GetAnotherProperty() { return AnotherProperty; } } 

    Another option is to put a property into a separate interface and implement it in a derived class, then the problem seems to be solved by itself, but sometimes this solution is not acceptable, for example, if in an abstract class there are implemented methods using this property.

    Well, the radical option is the rejection of the property as such, and a return to the classic methods GetXXX() and SetXXX(value) , this option is possible absolutely in any conditions and does not cause problems neither in interfaces nor in abstract classes, but worsens the readability of the code, Although this is certainly an amateur, in Java, for example, this is the only possible option, if lately there has not been a complete change in it.

    • Some strange, in my unenlightened view, a way around. Source position: we want to inherit a property with an override. The result of the workaround: we inherit the method with the redefinition, but about the property that we just needed, we should not forget to create it ourselves. - Bulson
    • @Bulson in this case there is almost no choice, just redefine this property will not work, why have already written. So the overlap is quite suitable if you want to save the property. - rdorn
    • one
      @rdorn is so logical for me, you take the implementation from an abstract class and redefine it, do not even redefine, but fundamentally change the implementation relative to the field (add setter). - ParanoidPanda
    • The @ParanoidPanda is just a matter of implementation, look at the original version. The property is declared abstract, there can be no implementation there, it is the same contract as the interface. And again, the properties are purely syntactic, sugar, so to speak, to reduce the amount of code. But the actual fields here have nothing to do with them; they are inherited as is and are not subject to redefinition. And then yes, we have to get away from redefining and use overlap to preserve external identity, and at the same time the internal mechanism changes - rdorn