Почему полное свойство в C# может быть переопределено только с помощью геттера, но его все равно можно установить?
Я столкнулся с поведением, которое меня удивляет. Даны следующие два класса:
class Parent
{
public virtual bool Property { get; set; }
}
class Child : Parent
{
public override bool Property { get => base.Property; }
}
Я могу написать код так:
Child child = new Child();
child.Property = true; // this is allowed
В среде IDE это также сбивает с толку, поскольку, хотя и разрешает присваивание, оно также указывает, что переопределенное свойство доступно только для чтения:
Кроме того, это переопределение разрешено только когда я использую базовый класс getter:
Что здесь происходит?
1 ответ
Я возьму трещину в этом.
Похоже, что это может быть просто ошибкой в Intellisense, когда он не может найти базовую реализацию авто-свойства. Код действителен и имеет смысл - вот еще один способ выразить ваш пример.
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();
}
С этим представлением теперь очевидно, почему переопределение GetProperty хорошо. Вот соответствующий IL для вашего кода:
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
И вот моя версия:
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
Обратите внимание, что это отличается от public override bool Property { get; }
является сокращением для указания компилятору сгенерировать одиночное переопределение геттера для свойства с тем же именем без упоминания ранее существовавшего сеттера. Однако, кто-то, имеющий опыт работы с настоящей спецификацией, наверняка сможет предложить больше информации об этом.