28

Why the property get the error while the method can be compiled?

public interface IFoo {}
public interface IBar<out T> where T : IFoo {}

public interface IItem<out T> where T: IFoo
{
    // IEnumerable<IBar<T>> GetList(); // works
    IEnumerable<IBar<T>> ItemList { get; set; } // Error!
}

Error:

Invalid variance: The type parameter 'T' must be contravariantly valid on 'UserQuery.IItem<T>.ItemList'. 'T' is covariant.

ca9163d9
  • 27,283
  • 64
  • 210
  • 413

2 Answers2

43

You get the compiler error because you have a property getter (get) and a setter (set). The property getter has the T in it's output so out works, but the property setter will have the T in its input so it would need the in modifier.

Because you have out on T you need to remove the setter and it will compile:

public interface IItem<out T> where T : IFoo
{
    // IEnumerable<IBar<T>> GetList(); // works
    IEnumerable<IBar<T>> ItemList { get; } // also works
}

If your T is an in generic argument then the following would work:

public interface IItem<in T> where T : IFoo
{
    IEnumerable<IBar<T>> ItemList { set; } 
}

But you cannot have both (out,in) at the same time so you cannot have a co/contravariant property with a getter and a setter.

nemesv
  • 138,284
  • 16
  • 416
  • 359
  • 6
    I don't understand this. You've related out,in to get,set. Why can't i use out, since out just means "this type or any derived type.". If B derives from A, then why cant I pass B to any property on the interface that requires an out A, since B will only be called as if it were an A anyway. What is the issue and what does in have to do with any of this? in says "this type or any base type". I don't want that as I'm expecting to use at least the behaviour set of A, passing an "a" will not cut it. So i wouldn't want "in"...but i do want to be able to set B into out A. – rism Jul 06 '14 at 05:59
3

The setter is not allowed, since if it were you would be able to do this:

public interface ISubFoo : IFoo { }

IItem<ISubFoo> item = //whatever
item.ItemList = new List<IBar<IFoo>>>();

which is not type safe.

Lee
  • 142,018
  • 20
  • 234
  • 287