为什么这个C#泛型委托不能赋值?

4
我想要一个引用委托的参考,该委托返回一个泛型接口的实例,其中类型参数是协变的。如果我在调用Get时指定了T的类型,则编译正常。但是在Get内部,我无法进行看似等效的赋值 - 尽管T被限制为IItem。
它说...
无法隐式将类型'System.Func'转换为'System.Func>'。存在一个显式转换(是否缺少强制转换?)
为什么会这样呢?
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;
        }
    }
}
1个回答

5
协变性只适用于引用类型 - 如果T是一个实现IItem的值类型,那么这将对你的代码造成问题。
为了使你的代码编译通过,你只需要约束T为引用类型即可。
public static Func<IA<T>> Get<T>() where T : class, IItem

作为一个稍微简单的示例(带有较少的泛型),我们可以使用IConvertible,它由stringint都实现:
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;

太棒了。谢谢。 - Ian
太棒了。谢谢。 - undefined
为了使您的代码编译通过,您只需要将T限制为类型。您是指引用类型吗? - DaveShaw
为了让你的代码编译通过,你只需要限制 T 为一个“值”类型。你是不是指引用类型? - undefined
@DaveShaw:是的,正在修复,谢谢。 - Jon Skeet
@DaveShaw: 是的,正在修复,谢谢。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接