31

I would like to only force the implementation of a C# getter on a given property from a base abstract class. Derived classes might, if they want, also provide a setter for that property for public use of the statically bound type.

Given the following abstract class:

public abstract class Base
{
    public abstract int Property { get; }
}

If I want a derived class that also implements a setter, I could naively try:

public class Derived : Base
{
    public override int Property
    {
        get { return field; }
        set { field = value; } // Error : Nothing to override.
    } 

    private int field;
}

But then I get a syntax error since I try to override the non existing setter. I tried some other way such as declaring the base setter private and such and I still stumble upon all kind of errors preventing me from doing that. There must be a way to do that as it doesn't break any base class contract.

Incidentaly, it can be done with interfaces, but I really need that default implementation.

I stumbled into that situation so often, I was wondering if there was a hidden C# syntax trick to do that, else I will just live with it and implement a manual SetProperty() method.

Coincoin
  • 27,880
  • 7
  • 55
  • 76

5 Answers5

20

You can't do it directly, since you can't new and override with the same signature on the same type; there are two options - if you control the base class, add a second property:

public abstract class Base
{
    public int Property { get { return PropertyImpl; } }
    protected abstract int PropertyImpl {get;}
}
public class Derived : Base
{
    public new int Property {get;set;}
    protected override int PropertyImpl
    {
        get { return Property; }
    }
}

Else you can introduce an extra level in the class hierarchy:

public abstract class Base
{
    public abstract int Property { get; }
}
public abstract class SecondBase : Base
{
    public sealed override int Property
    {
        get { return PropertyImpl; }
    }
    protected abstract int PropertyImpl { get; }
}
public class Derived : SecondBase
{
    public new int Property { get; set; }

    protected override int PropertyImpl
    {
        get { return Property; }
    }
}
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Your solutions are interesting, I will ponder a little on them. – Coincoin Sep 28 '09 at 21:39
  • 1
    Your solution is what is the closest to the thing. But I don't think it's possible to do it without forcing the derived class to do acrobatics. – Coincoin Sep 29 '09 at 14:42
7

Would this suit your needs?

public abstract class TheBase
{
    public int Value
    {
        get;
        protected set;
    }
}
public class TheDerived : TheBase
{
    public new int Value
    {
        get { return base.Value; }
        set { base.Value = value; }
    }
}

The virtual was removed, but the base value is still the only storage for the value. So this should show '5'. And the compiler should fuss about b.Value = 4;

TheDerived d = new TheDerived();
d.Value = 5;
TheBase b = d;
//b.Value = 4;    // uncomment for compiler error
cout << "b.Value == " << b.Value << endl;

-Jesse

Jesse Chisholm
  • 3,857
  • 1
  • 35
  • 29
3

What about something like:

public abstract class Base
{
    public virtual int Property
    {
        get { return this.GetProperty(); }
        set { }
    }

    protected abstract int GetProperty();
}
Rex M
  • 142,167
  • 33
  • 283
  • 313
  • 1
    Any inheritor now has to override both of them - a bit redundant? – Marc Gravell Sep 28 '09 at 21:24
  • Only if overriding the property. Else, without the virtual property that could actually be an acceptable alternative. – Coincoin Sep 28 '09 at 21:34
  • 1
    If you don't override the property, the purpose of the set is very... unusual. – Marc Gravell Sep 28 '09 at 21:38
  • You are right, I totally misread the answer. It has to be newed somewhere. – Coincoin Sep 28 '09 at 21:40
  • @Marc as far as I can tell it accomplishes the requirement, with the only caveat that adding a setter requires also a getter which just calls base. – Rex M Sep 28 '09 at 21:52
  • It's a tie but I chose the other answer because I don't feel at ease with the empty setter in the base class. However, I don't think there is a perfectly good answer. – Coincoin Sep 29 '09 at 14:43
1

I had a similar requirement where I needed an interface to be able to share common sorting functionality between two loosely related classes. One of them had a read-only Order property and the other had a read-write Order property, but I needed a way to read the property the same way from both classes.

It turns out that this can be done by hiding the read-only value in a derived interface. Here is how I did it.

interface ISortable
{
    int Order { get; }
}

interface ISortableClass2
    : ISortable
{
    // This hides the read-only member of ISortable but still satisfies the contract
    new int Order { get; set; }
}

class SortableClass1
    : ISortable
{
    private readonly int order;

    public SortableClass1(int order)
    {
        this.order = order;
    }

    #region ISortable Members

    public int Order
    {
        get { return this.order; }
    }

    #endregion
}

class SortableClass2
    : ISortableClass2
{
    #region ISortableClass2 Members

        public int Order { get; set; } 

    #endregion
}

class RunSorting
{
    public static void Run()
    {
        // Test SortableClass1
        var list1 = new List<SortableClass1>();

        list1.Add(new SortableClass1(6));
        list1.Add(new SortableClass1(1));
        list1.Add(new SortableClass1(5));
        list1.Add(new SortableClass1(2));
        list1.Add(new SortableClass1(4));
        list1.Add(new SortableClass1(3));

        var sorted1 = SortObjects(list1);

        foreach (var item in sorted1)
        {
            Console.WriteLine("SortableClass1 order " + item.Order);
        }

        // Test SortableClass2
        var list2 = new List<SortableClass2>();

        list2.Add(new SortableClass2() { Order = 6 });
        list2.Add(new SortableClass2() { Order = 2 });
        list2.Add(new SortableClass2() { Order = 5 });
        list2.Add(new SortableClass2() { Order = 1 });
        list2.Add(new SortableClass2() { Order = 4 });
        list2.Add(new SortableClass2() { Order = 3 });

        var sorted2 = SortObjects(list2);

        foreach (var item in sorted2)
        {
            Console.WriteLine("SortableClass2 order " + item.Order);
        }
    }

    private static IEnumerable<T> SortObjects<T>(IList<T> objectsToSort) where T : ISortable
    {
        if (objectsToSort.Any(x => x.Order != 0))
        {
            return objectsToSort.OrderBy(x => x.Order);
        }

        return objectsToSort;
    }
}
NightOwl888
  • 55,572
  • 24
  • 139
  • 212
-1

You may do this with a constructor as following;

public abstract class Base
{
    public abstract int Property { get; }
}


public class Derived : Base
{
    public Derived(string Property) : base(Property)
    {

    }
}
zalky
  • 659
  • 1
  • 7
  • 12