Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IList using covariance and contravariance in c#, is this possible?

would this be possible? (I don't have vs. 2010, so I can't try it myself, sorry)

public interface IComplexList<out TOutput, in TInput> where TOutput : TInput
{
    public IEnumerator<TOutput> GetEnumerator();
    public void Add(TInput item);
}

public interface IList<T> : IComplexList<T, T>
{
}

If I get it right, you could use this to actually implement covariance and contravariance in the same interface.

like image 659
Daniel Fabian Avatar asked Aug 11 '09 08:08

Daniel Fabian


2 Answers

Well, your question is slightly confusing because of the existing IList<T> type. However, the following does compile:

public interface IComplexList<out TOutput, in TInput> where TOutput : TInput
{
    IEnumerator<TOutput> GetEnumerator();
    void Add(TInput item);
}

public interface ISimpleList<T> : IComplexList<T, T>
{
}

You can even change it to extend IEnumerable<TOutput>:

public interface IComplexList<out TOutput, in TInput>
    : IEnumerable<TOutput>
    where TOutput : TInput
{        
    void Add(TInput item);
}

public interface ISimpleList<T> : IComplexList<T, T>
{
}

The indexer is tricky, because you'd want different types involved. You could do:

TOutput Get(int index);
void Set(int index, TInput item);

and then put the indexer into ISimpleList<T> instead of course...

That doesn't let you use ISimpleList<T> variantly though, because you've basically forced TInput=TOutput.

An alternative approach is to separate out the input from the output:

public interface IReadableList<out T> : IEnumerable<T>
{
    T Get(int index);
}

public interface IWritableList<in T>
{
    void Add(T item);
    void Set(int index, T item);
}

 public interface IMyList<T> : IReadableList<T>, IWritableList<T> {}

Then you could write:

public void Foo(IWritableList<string> x) { ... }

IMyList<object> objects = new MyList<object>();
Foo(objects);

and vice versa for IReadableList. In other words, you allow variance for each side individually, but you never get variance for the two sides together.

like image 135
Jon Skeet Avatar answered Sep 27 '22 23:09

Jon Skeet


No, you can't. In your example IList<T> is invariant. IList<T> would require to declare in/out to be covariant/contravariant. It's not possible to do that just by inheriting some interface that is covariant.

like image 39
mmx Avatar answered Sep 27 '22 23:09

mmx