Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why doesn't this C# generic delegate assign?

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?)

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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;
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading