Abstract property with public getter, define private setter in concrete class possible?
I'm trying to create an abstract class that defines a property with a getter. I want to leave it up to derived classes to decide if they want to implement a setter for the property or not. Is this possible?
What I have so far:
public abstract class AbstractClass {
public abstract string Value { get; }
public void DoSomething() {
Console.WriteLine(Value);
}
}
public class ConcreteClass1 : AbstractClass {
public override string Value { get; set; }
}
public class ConcreteClass2 : AbstractClass {
private string _value;
public override string Value {
get { return _value; }
}
public string Value {
set { _value = value; }
}
}
public class ConcreteClass3 : AbstractClass {
private string _value;
public override string Value {
get { return _value; }
}
public void set_Value(string value) {
_value = value;
}
}
In ConcreteClass1
, I get an error on the set
. It can't override set_Value
because no overridable set accessor exists in AbstractClass.
In ConcreteClass2
, I get an error on both Value
's because a member with the same name is already declared.
ConcreteClass3
doesn't give an error, but even though Value's set accessor would be compiled into set_Value, it doesn't work the other way around. Defining a set_Value
does not mean that Value
gets a set accessor. So I can't assign a value to a ConcreteClass3.Value property. I can use ConcreteClass3.set_Value("value"), but that's not what I'm trying to achieve her开发者_Python百科e.
Is it possible to have the abstract class demand a public getter, while allowing an optional setter to be defined in a derived class?
In case you'r wondering, this is just a theoretical question. I don't have a real situation where something like this is needed. But I can imagine an abstract class that doesn't care how a property gets set, but that does need to be able to get the property.
Unfortunately, you can't do exactly what you want. You can do this with interfaces though:
public interface IInterface {
string MyProperty { get; }
}
public class Class : IInterface {
public string MyProperty { get; set; }
}
The way I would do it is to have a separate SetProperty method in the concrete classes:
public abstract class AbstractClass {
public abstract string Value { get; }
}
public class ConcreteClass : AbstractClass {
private string m_Value;
public override string Value {
get { return m_Value; }
}
public void SetValue(string value) {
m_Value = value;
}
}
Found a solution: How to override a getter-only property with a setter in C#?
public abstract class A
{
public abstract int X { get; }
}
public class B : A
{
public override int X { get { return 0; } }
}
/*public class C : B //won't compile: can't override with setter
{
private int _x;
public override int X { get { return _x; } set { _x = value; } }
}*/
public abstract class C : B //abstract intermediate layer
{
public sealed override int X { get { return this.XGetter; } }
protected abstract int XGetter { get; }
}
public class D : C //does same thing, but will compile
{
private int _x;
protected sealed override int XGetter { get { return this.X; } }
public new virtual int X { get { return this._x; } set { this._x = value; } }
}
D
is now equivalent to a class inheriting from B
while also being able to override in a setter.
You can just use protected
access modifier instead. Because of inheritance you are not allowed to use private
. It looks like so:
public abstract class A
{
public abstract int prop { get; protected set; }
}
public abstract class B : A
{
public override int prop { get; protected set; }
}
Not very elegant, but it's the closest you can get without doing something like you have in concreteclass3
public class Concrete : AbstractClass
{
public new void DoSomething()
{
Console.WriteLine(Value);
}
}
public abstract class AbstractClass
{
protected AbstractClass()
{
try
{
var value = Value;
}
catch (NotImplementedException)
{
throw new Exception("Value's getter must be overriden in base class");
}
}
public void DoSomething()
{
Console.WriteLine(Value);
}
/// <summary>
/// Must be override in subclass
/// </summary>
public string Value { get { throw new NotImplementedException(); } }
}
精彩评论