1

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;}
}

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.

Patrick Szalapski
  • 8,738
  • 11
  • 67
  • 129
Tipx
  • 7,367
  • 4
  • 37
  • 59
  • Note : For the time being, I added the setter in the BaseClass and I throw an NotImplementedException for all the ChildClass that don't need to implement it. – Tipx Apr 25 '11 at 04:07
  • This feature has been under consideration since 2016. See https://github.com/dotnet/csharplang/issues/1568 for its current status. – Brian Mar 22 '19 at 18:37

4 Answers4

4

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.

Tieson T.
  • 20,774
  • 6
  • 77
  • 92
  • I'll go with this, but slightly modified. I still need my BaseClass class, but I'll add an IClass interface for this, and other more interface like things. Thanks! – Tipx Apr 25 '11 at 14:21
  • Ah, thanks for that, I was suffering under the most irritating misapprehension that you couldn't implement a set, if the interface property didn't have one. – Rich Oliver Mar 04 '12 at 20:43
1

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; }
}
Rick Sladkey
  • 33,988
  • 6
  • 71
  • 95
0

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.

kimewaza
  • 82
  • 1
  • 7
  • The exception is there to make sure it's never called. If it's ever called in my child class mechanics, there is really something wrong going on!!! – Tipx Apr 25 '11 at 14:19
  • That looks bad to me. On many occasions I've tried to set a non existent setter and the compiler very helpfully errors me that its not there. An empty setter would give the appearance of being a setter when it wasn't. – Rich Oliver Mar 04 '12 at 20:48
-1

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.

Community
  • 1
  • 1
Patrick Szalapski
  • 8,738
  • 11
  • 67
  • 129
  • 1
    I'm still not convinced of this argument. Any code that depended on there being a getter would still work if you added a setter. It just doesn't make sense as part of the contract. Consider how easy it is to work around by just having explicit setter and getter methods (like you must have in, e.g., Java and C++) and added a setter method in a derived class there would not be considered a violation of contract. – siride Apr 25 '11 at 04:41
  • Having explicit setter/getter is still possible in .NET; it was a language design decision to add Properties to the language, and to make the "read-onlyness" of a property as part of the contract rather than a mere "omitted method". VB.NET makes this more explicit with its ReadOnly keyword, but the same feature is in C#. – Patrick Szalapski May 31 '11 at 22:40
  • 1
    I can understand it being some arbitrary decision on the part of the VB folks, but I disagree still that it violates fundamental principles. You are adding functionality and you are not changing existing functionality or otherwise violating the Liskov Substitution Principle. You could think of it this way: the base class says "I know, at most, how to provide the value for this property". And then a derived class comes along and says "I can provide this value, but I also know a way to change it". It's like the classic case of a shape class that has an Area() function and derived classes... – siride Jun 01 '11 at 04:37
  • ...have ways of actually setting the shape's parameters so that area can be calculated (such as having length and width, or circumference). – siride Jun 01 '11 at 04:38