9

I have this simple code :

public interface IReader<out T>
{
    IEnumerable<T> GetData();
}

This interface should be covariant on T, and i'm using it this way :

private static Func<bool> MakeSynchroFunc<T>(IReader<T> reader) where T : IComposite
{
    return () => Synchronize(reader);
}

Note the constraint for T to implement IComposite. The synchronization method takes an IReader<IComposite> in input :

private static bool Synchronize(IReader<IComposite> reader)
{
    // ......
}

The compiler tells me it cannot convert from IReader<T> to IReader<IComposite> despite the constraint on T and the covariance of IReader.

Is there something i'm doing wrong here ? The compiler should be able to verify the constraint and the covariance should let me use my IReader<T> as an IReader<Icomposite>, isn't it ?

Thanks.

dou bret
  • 267
  • 2
  • 11
  • 3
    What if `T` were a struct? Then the variance rules would be broken. You need a `class` constraint to satisfy the compiler that it will be an identity-preserving conversion. See: [Is this a covariance bug in C# 4?](http://stackoverflow.com/questions/2783233/is-this-a-covariance-bug-in-c-sharp-4) – Ani Jun 20 '12 at 13:11
  • yes, that was the problem, it works fine now. thank you – dou bret Jun 20 '12 at 13:30
  • possible duplicate of [Why covariance does not work with generic method](http://stackoverflow.com/questions/12743444/why-covariance-does-not-work-with-generic-method) – nawfal Jul 07 '14 at 07:03

3 Answers3

5

You should be able to resolve your issue by adding a class constraint to T. Covariance does not work when structs are involved (IEnumerable<int> would not be convertible to IEnumerable<object>). Since you have not constrained T to be a class, you could pass in an IReader<some struct that implements IComposite>, which would not be convertible.

Gideon Engelberth
  • 6,095
  • 1
  • 21
  • 22
  • cool, it works now, i already knew that covariance was not working with value types but didn't realize that this was the cause of my problem in this case. adding the class constraint makes it work perfectly. thank you !! – dou bret Jun 20 '12 at 13:27
1

Unfortunately not. Generics are not covariant. IReader<T> and IReader<IComposite> are totally unrelated types, despite T being related to IComposite.

EDIT: I do not know why this would not work with .Net 4 and <out T>. Can anyone else answer?

GazTheDestroyer
  • 20,722
  • 9
  • 70
  • 103
  • 1
    are you sure ? the out specifier on the IReader interface definition should tell the compiler that the interface is covariant. i'm using .NET 4 – dou bret Jun 20 '12 at 12:34
  • 3
    This answer needs clarifying; it's rather confusing as written. – Jeff Yates Jun 20 '12 at 12:35
  • I did not know about the keyword for interface covariance, and having read about it I cannot see why the OP's code would not work. +1 for question since I learned something, and hopefully someone else can answer. – GazTheDestroyer Jun 20 '12 at 13:07
  • thank you for having tried to help. i don't understand why it doesn't work also. – dou bret Jun 20 '12 at 13:12
0

Why not change the function definition, since this is what you really want anything:

private static Func<bool> MakeSynchroFunc<T>(IReader<IComposite> reader) where T : IComposite

You might need the generic parameter T for other things, so I left it there.

zmbq
  • 38,013
  • 14
  • 101
  • 171
  • because i need the parameter T for something else, this was just an example, not the real code. and i would like to let the compiler infer the type of T instead of having to specify it explicitely. – dou bret Jun 20 '12 at 12:31