I want a reference to a delegate that returns an instance of a generic interface, where the type parameter is covariant. If I specify the type of T
when calling Get
then it compiles ok. But within Get
, I can’t make what looks like an equivalent assignment – despite T
being constrained to IItem
.
It says…
Cannot implicitly convert type ‘System.Func<GetSetContext.A>’ to
‘System.Func<GetSetContext.IA<GetSetContext.IItem>>’. An explicit
conversion exists (are you missing a cast?)
Why is this?
using System;
using System.Collections.Generic;
using System.Linq;
namespace MyNamespace
{
public interface IA<out T>
{
IEnumerable<T> f();
}
public class A<T> : IA<T>
{
public IEnumerable<T> f()
{
return Enumerable.Empty<T>();
}
}
public interface IItem {}
public class Item : IItem {}
public static class Program
{
public static void Main(string[] args)
{
Func<IA<IItem>> a = Get<Item>();
}
public static Func<IA<T>> Get<T>() where T : IItem
{
var x = () => new A<T>();
//Doesn't compile
Func<IA<IItem>> a = x;
return x;
}
}
}
>Solution :
Covariance only works for reference types – which would cause a problem for your code if T
were a value type implementing IItem
.
All you need to do in order to make your code compile is constrain T
to be a value type:
public static Func<IA<T>> Get<T>() where T : class, IItem
As a slightly simpler example (with fewer generics), we can use IConvertible
which is implemented by both string
and int
:
Func<string> x = () => "";
Func<int> y = () => 0;
// This is fine, as string is a
// reference type implementing IConvertible
Func<IConvertible> x2 = x;
// This doesn't compile, because the
// covariant conversion isn't available:
// int is a value type (even though it
// implements IConvertible)
Func<IConvertible> y2 = y;