开发者

C#: Semi-Abstract Automatic Properties?

In a base class, I want to define an abstract get, but at that point, I don't care about the set. How can I define a setter in my child class?

I tried a few things, but I can't get it to work. For example I tried :

public class BaseClass
{
    public abstract bool MyBool { get; }
}

public class ChildClass : BaseClass
{
    public override bool MyBool { get; protected set;}
}

And :

public class BaseClass
{
    public bool MyBool { abstract get; }
}

public class ChildClass : BaseClass
{
    public bool MyBool { override get; protected set;}
}
开发者_JAVA技巧

I know I can workaround this by not using automatic properties in the child class and directly setting the underlying field instead of creating a setter, but I'm looking for something better.

Edit: I don't want to add an abstract setter in the BaseClass.


It may make more sense to use an interface rather than a base class. Then you simply have the classes that need to provide that property implement that interface.

For instance, you can create this interface:

public interface IBoolable {
     bool MyBool { get; }
}

Then it is still valid to implement the interface like so:

public class BoolableItem : IBoolable {
     public bool MyBool { get; protected set; }
}

Done this way, your code can safely assume anything that implements IBoolable has a property called MyBool that is at minimum read-only.


One solution is to make MyProperty not abstract but delegate its implementation to an abstract protected property that children must override:

public abstract class BaseClass
{
    public bool MyBool { get { return MyBoolInternal; } }
    protected abstract bool MyBoolInternal { get; set; }
}

public class ChildClass : BaseClass
{
    protected override bool MyBoolInternal { get; set; }
}


You have to make up your mind what behavior you want: if it is defined as abstract then a deriving class MUST implement it.

So what you should do is this:

public abstract class BaseClass
{
    public abstract string MyProperty { get; set; }
}


public class DerivedClass : BaseClass
{
    public override string MyProperty
    {
        get { return "myValue"; }
        set { /* do nothing, not applicable for this class */ }
    } 
}

Don't throw the NotImplementedException - that is not what you want, you simply want the setter to do nothing for some child classes.


To leave it ambiguous whether you want a setter in inherited classes would violate OOP principles--that is, if a class (abstract or not) has a public/protected setter (abstract or not), then all inheriting classes must also; if a class does not, then inheriting classes must not.

Another way to think about this is to consider properties such that read-only or read-write is part of the contract of the class. Since instances of inheriting classes must adhere to an "Is-a relationship" (the LSP), inheriting classes cannot "add a setter" where the main class didn't have one, because the fact that the main class had a property without as setter is part of the main class definition. In effect, since the main class cannot change the property in question via a setter, therefore all inheriting classes MUST guarantee the same behavior.

Consider using a protected backing field; then you can split this property into a read-only property and a separate setter method. Then, the main class can have the property only and the subclass can have a setter method that the main class doesn't know about. However, I'm not sure this would be a good design either.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜