Wednesday, April 6, 2011

Generic implementation of interface

Hi everyone! Why isn't this working ?

public interface IPoint
{
  // not important
}

public interface IPointList
{
  List<IPoint> Points { get; }
}

public abstract class Point : IPoint
{
  // implemented IPoint
}

public abstract class PointList<TPointType> : IPointList
  where TPointType: IPoint
{
  public abstract List<TPointType> Points { get; } // <- doesn't compile
}

The TPointType obviously has to be an IPoint. Why this implementation is not allowed ?

regards, Kate

From stackoverflow
  • The class PointList should implement the IPointList interface. Methods/properties cannot differ by return type only, which is what you're trying to do with the Points declaration in class PointList. If you implement

    List<TPointType> Points { get; }
    

    then logically you cannot implement

    List<IPoint> Points { get; }
    

    Because they would differ by return type only.

    SmartK8 : Ok. So the interface - as far as types are concerned - has to be as it is. Is there any way how to have the best of both worlds. So descendants can have generics and also the interface is satisfied ? Because this way I've to have Points and also some other property List GenericPoints ?
    Lasse V. Karlsen : Make the interface generic.
    SmartK8 : In my case the generic interfaces are a road to hell. I tried that first I ended up with six parameters long interfaces. This example is not what I'm really trying to implemented (which several multitudes more complex). Thx for the comment thou.
  • As an answer to your comment, on how to get best of both worlds; I was thinking of something like this, where you implement your interface GetPoints property explictily, create a GetPoints property that is 'more typed', and an protected abstract method that you can override in concrete implementations.
    The 2 properties call the abstract implementation.

        public abstract class PointList<T> : IPointList where T : IPoint
        {
            public IList<T> GetPoints
            {
                get
                {
                    return GetPointsCore ();
                }
            }
    
            IList<IPoint> IPointList.GetPoints
            {
                get
                {
                    return GetPointsCore () as IList<IPoint>;
                }        
            }
    
            protected abstract IList<T> GetPointsCore();        
        }
    
    SmartK8 : Elegant. Thanks that is exactly what I was after and it works like a charm.
    configurator : This could would always return null when used like this: { PointList list = new PointList(); var x = ((IPointList)list).GetPoints; } in this case x will be null because IList cannot be cast to an IList (at least not until C# 4.0 in VS 2010).
    configurator : Now that I think about it, this wouldn't work in C# 4.0 either because an IList is not covariant.

0 comments:

Post a Comment