0

This is what I want my classes to look like, but this code won't compile. How do I make it work?

public interface ISomeInterface
{
    string AMember { get; }
}
public abstract class BaseClass
{
    public abstract ISomeInterface AObject { get; }
    public abstract IEnumerable<ISomeInterface> AMethod();
}

public class DerivedClass<T> : BaseClass where T : ISomeInterface
{
    public T AObject { get; private set; }
    public IEnumerable<T> AMethod()
    {
        return null;
    }
}

Compiler errors

'Delfin.Accountancy.DerivedClass' does not implement inherited abstract member 'Delfin.Accountancy.BaseClass.AObject.get'

'Delfin.Accountancy.DerivedClass' does not implement inherited abstract member 'Delfin.Accountancy.BaseClass.AMethod()'

Running on c# 5.0.

Notes

I've tried most obvious implementations, but any of them allow me to implement the base class and expose the strongly typed members at once.

I don't want to make the base class generic, because I'll create static methods on the base class, and also create extension methods that might work in every case of derived classes.

I also need the derived class to be generic, because T has more members than ISomeInterface in the real world case.

Thanks!

LMB
  • 1,137
  • 7
  • 23
  • won't compile means what compilation error? what C# version are you using? – Tallmaris Nov 11 '12 at 18:25
  • 1
    For the code to compile, the abstract methods of the base class must be overriden in the derived class. Why don't you change the base class to a generic class? – Panos Rontogiannis Nov 11 '12 at 18:32
  • In order to derive from `BaseClass` you must override its abstract member or make derived class abstract. – Hamlet Hakobyan Nov 11 '12 at 18:34
  • @Panos I want to create static members on the base class, that are non-generic. Also I want to create extensions methods over the base class. – LMB Nov 11 '12 at 18:34

4 Answers4

2

What you are asking for is called return type covariance and C# does not support this (see this answer for more details). You have to modify your classes in some way but you haven't indicated what is acceptable. Here is a way that does not change the public API, but changes the abstract methods to protected methods.

public interface ISomeInterface
{
    string AMember { get; }
}

public abstract class BaseClass
{
    public ISomeInterface AObject { get { return GetAObjectImpl(); } }     
    public IEnumerable<ISomeInterface> AMethod() { return AMethodImpl(); }

    protected abstract ISomeInterface GetAObjectImpl();
    protected abstract IEnumerable<ISomeInterface> AMethodImpl();
}

public class DerivedClass<T> : BaseClass where T : ISomeInterface
{
    public new T AObject { get; private set; }

    public new IEnumerable<T> AMethod() { return Enumerable.Empty<T>(); }

    protected override ISomeInterface GetAObjectImpl() 
    {
        return AObject;
    }

    protected override IEnumerable<ISomeInterface> AMethodImpl()
    {
        return AMethod();
    }
}
Community
  • 1
  • 1
Mike Zboray
  • 39,828
  • 3
  • 90
  • 122
0

Not sure what you're trying to achieve here. Your DerivedClass AObject and IEnumerable effectively hide the base class' declarations. What's your reasoning for wanting your derived class' signature take an interface as its generic parameter?

This will compile:

    public interface ISomeInterface
    {
        string AMember { get; }
    }
    public abstract class BaseClass
    {
        public abstract ISomeInterface AObject { get; protected set; }
        public abstract IEnumerable<ISomeInterface> AMethod();
    }

    public class DerivedClass<T> : BaseClass where T : ISomeInterface
    {
        public override ISomeInterface AObject { get; protected set; }
        public override IEnumerable<ISomeInterface> AMethod()
        {
            return null;
        }
    }
Anthill
  • 1,219
  • 10
  • 20
  • And why `DerivedClass` is generic? – Hamlet Hakobyan Nov 11 '12 at 18:35
  • @Hamlet I'd like to know too :) – Anthill Nov 11 '12 at 18:37
  • Because T have more members than ISomeInterface. T is a data object. DerivedClass processes data over a array of T. The same goes for BaseClass and ISomeInterface. – LMB Nov 11 '12 at 18:39
  • @Lmb well that makes sense but only if you're planning to have many different classes of type T: ISomeInterface with different base classes. – Anthill Nov 11 '12 at 19:15
  • @Anthill Actually ISomeInterface is a represents a ComplexType (a group of columns that are usualy together in many databases, in this case, ITransactionCostDetails, that are used for several calculations), and there are many types DerivedClass. Thanks! – LMB Nov 11 '12 at 19:21
  • @Lmb that completes the puzzle - always useful to know the intention behind the design ;) – Anthill Nov 11 '12 at 19:29
0

To make it work you can make your base class generic:

public interface ISomeInterface
{
    string AMember { get; }
}
public abstract class BaseClass<T> where T : ISomeInterface
{
    public abstract T AObject { get; protected set; }
    public abstract IEnumerable<T> AMethod();
}

public class DerivedClass<T> : BaseClass<T> where T : ISomeInterface
{
    public override T AObject { get; protected set; }
    public override IEnumerable<T> AMethod()
    {
        return null;
    }
}
tukaef
  • 9,074
  • 4
  • 29
  • 45
0

Why not:

public interface ISomeInterface
{
    string AMember { get; }
}
public abstract class BaseClass
{
    public abstract ISomeInterface AObject { get; protected set; }
    public abstract IEnumerable<ISomeInterface> AMethod();
}

public class DerivedClass : BaseClass
{
    public override ISomeInterface AObject { get; protected set; }
    public override IEnumerable<ISomeInterface> AMethod()
    {
        return null;
    }
}

You can return any type which implements ISomeInterface interface in AObject property and, because IEnumearable<T> is covariant you can return any enumerable of ISomeInteface implemented class.

Hamlet Hakobyan
  • 32,965
  • 6
  • 52
  • 68
  • T has more members than ISomeInterface in the real world case, and DerivedClass must be aware of them. – LMB Nov 11 '12 at 18:58