Jordi
Jordi

Reputation: 23277

C# Covariance generic parameter assignment/casting (implicit conversion)

I've a interface:

interface IInterface<T1, out T2> {};

and an abstract class implements IInterface<>

abstract class AbsClass<T2> : IInterface<String, T2> {};

and other abstract classes inherits from AbsClass<>:

abstract class AbsAbsClassString : AbsClass<String, String> {};
abstract class AbsAbsClassTimeSpan : AbsClass<String, TimeSpan> {};

and finally,

class CClassString1 : AbsAbsClassString {};
class CClassString2 : AbsAbsClassString {};
class CClassTimeSpan1 : AbsAbsClassTimeSpan {};
class CClassTimeSpan2 : AbsAbsClassTimeSpan {};
// and so on...

In my C3 code, I've declared a List<IInterface<String, Object>>

IList<IInterface<String, Object>> list = new List<IInterface<String, Object>>();
list.Add(new CClassString1());
list.Add(new CClassString2());
list.Add(new CClassTimeSpan1());
list.Add(new CClassTimeSpan2());

On each list.Add(*) sentence, compiler tells me:

The best overloaded method match for 'System.Collections.Generic.ICollection(IInterface(String,object)).Add(IInterface(String,object))' has some invalid arguments

Argument 1: Cannot implicitly convert type CClassString1 to IInterface(String,object). An explicit conversion exists (are you missing a cast?)

If I test with:

IInterface<String, Object> i;
CClassString1 cs1 = new CClassString1();

i = (Interface<String,Object>)cs1;

The last sentence throw an exception telling it's impossible to do the cast.

Upvotes: 0

Views: 431

Answers (1)

Jakub Lortz
Jakub Lortz

Reputation: 14904

Generic interface convariance and contravariance only works with reference types. TimeSpan is a value type, so IInterface<string, TimeSpan> cannot be cast to IInterface<string, object>.

That's because variant casts are reference conversions - they do not change the representation of the object, they only change the compile-time type of the reference.

Upvotes: 2

Related Questions