Why Is It Impossible to Override a Getter-Only Property and Add a Setter

How to override a getter-only property with a setter in C#?

Be careful with your solution as it hides the original intent for A and B. That being said, your solution does work, even when casting to base classes.

Example:

D d = new D();
d.X = 2;
B b = d as B;

Assert.AreEqual(2, b.X);

If the base classes can be modified, I recommend using reflection.

Override get, but not set

New in C# 6.0:

If you are only calling the setter within your constructor, you can resolve this problem using read-only properties.

void Main()
{
BaseClass demo = new DClass(3.6);
}

public abstract class BaseClass
{
public abstract double MyPop{ get; }
}

public class DClass : BaseClass
{
public override double MyPop { get; }
public DClass(double myPop) { MyPop = myPop;}
}

Why can a full property in C# be overridden with only a getter but it can still be set?

I'll take a crack at this.

It looks like this may just be a bug with Intellisense, where it is unable to find the base implementation of an auto-property. The code is valid and makes sense - here's another way to express your example.

Child child = new Child();
child.SetProperty(true);

class Parent
{
private bool _property;

public virtual bool GetProperty() => _property;
public virtual void SetProperty(bool value) => _property = value;
}

class Child : Parent
{
public override bool GetProperty() => base.GetProperty();
}

With this representation, it's now obvious why overriding GetProperty is fine. Here's the relevant IL for your code:

Main:
IL_0000: newobj Child..ctor
IL_0005: ldc.i4.1
IL_0006: callvirt Parent.set_Property
IL_000B: ret

Parent.get_Property:
IL_0000: ldarg.0
IL_0001: ldfld Parent.<Property>k__BackingField
IL_0006: ret

Parent.set_Property:
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld Parent.<Property>k__BackingField
IL_0007: ret

Parent..ctor:
IL_0000: ldarg.0
IL_0001: call System.Object..ctor
IL_0006: ret

Child.get_Property:
IL_0000: ldarg.0
IL_0001: call Parent.get_Property
IL_0006: ret

Child..ctor:
IL_0000: ldarg.0
IL_0001: call Parent..ctor
IL_0006: ret

And here's my version:

Main:
IL_0000: newobj Child..ctor
IL_0005: ldc.i4.1
IL_0006: callvirt Parent.SetProperty
IL_000B: ret

Parent.GetProperty:
IL_0000: ldarg.0
IL_0001: ldfld Parent._property
IL_0006: ret

Parent.SetProperty:
IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld Parent._property
IL_0007: ret

Parent..ctor:
IL_0000: ldarg.0
IL_0001: call System.Object..ctor
IL_0006: ret

Child.GetProperty:
IL_0000: ldarg.0
IL_0001: call Parent.GetProperty
IL_0006: ret

Child..ctor:
IL_0000: ldarg.0
IL_0001: call Parent..ctor
IL_0006: ret

Note that this is different than public override bool Property { get; }, being shorthand for instructing the compiler to generate a single getter override for a backing property of the same name, with no mention of the preexisting setter. Somebody experienced with the actual spec will definitely be able to offer more information around this, however.

Override both getter and setter of a property

From my observations, I think you are supposed to use the @Base.value.setter (or .getter) decorator if only the setter (or getter) needs to be overwritten.

If you have to override both, just use the usual @property approach.

class Base():
def __init__(self):
self._value = 'Value'

@property
def value(self):
print('Base.Getter')
return f'Base.{self._value}'

@value.setter
def value(self, value):
print('Base.Setter')
self._value = value

class Child(Base):
@property
#@Base.value.getter
def value(self):
print('Child.Getter')
return f'Child.{self._value}'

@value.setter
#@Base.value.setter
def value(self, value):
print('Child.Setter')
self._value = value

b, c = Base(), Child()
print(b.value)
print(c.value)
b.value = 'test.base'
c.value = 'test.child'
print(b.value)
print(c.value)

prints:

Base.Getter
Base.Value
Child.Getter
Child.Value
Base.Setter
Child.Setter
Base.Getter
Base.test.base
Child.Getter
Child.test.child

Override a setter, and the getter must also be overridden

Yes, this is intentional (a part of the spec). If an object has an own property (.property in your example), this property will be used and not an inherited one. If that property is existent, but is an accessor property without a getter, then undefined will be returned.

Notice that this behaviour has not changed from ES5.

Adding setters to properties in overrides

The interface declares what public properties the class must have (It's just a contract). Which means you need to have those properties, but can add to them.

The abstract class declares the actual structure of those properties. So if you don't have the setter in the abstract base, you can't add to it in the implementation.

When you write the override modifier it looks in the base class for something to override.

Overriding a Get/Set Property to Be Get-Only Still Lets You Set It

By looking at the generated CIL code, it turns out that your are overriding the getter method by makking it read only in the derived class:

public override bool Property => property;

but still inheriting the setter, so when you set the property, you still have access to the setter method of the base class.

How do I override the setter method of a property in C#?

The override is fine. However, as the error message states, you need to mark the property in the base class as virtual to be able to override it:

public virtual Vector2 Position

Unlike Java, class members are not virtual by default in C#. If you can't change the base class, you're out of luck.



Related Topics



Leave a reply



Submit