2

类型差异让我很头疼。我的印象是out方差修饰符IEnumerable<out T>应该允许这种行为。

interface ISampleInterface
{

}

/// <summary>
/// This works great!
/// </summary>
static void GenericMethod<TSeq>(TSeq sequence) where TSeq : IEnumerable<ISampleInterface>
{
    UseInterface(sequence);
}

/// <summary>
/// This does not compile :(
/// </summary>
static void GenericMethod<T>(IEnumerable<T> sequence) where T : ISampleInterface
{
    UseInterface(sequence);
}

static void UseInterface(IEnumerable<ISampleInterface> item)
{
    throw new NotImplementedException();
}

错误是;

错误 CS1503 参数 1:无法从转换System.Collections.Generic.IEnumerable<T>System.Collections.Generic.IEnumerable<ISampleInterface>

为什么GenericMethod<T>编译失败,但GenericMethod<TSeq>编译得很好?

4

1 回答 1

4

问题是方差(例如IEnumerable<out T>)仅适用于参考转换。你不能这样做:

IEnumerable<object> x = new List<int>(); // Boxing conversion
IEnumerable<long> x = new List<int>();   // User-defined type conversion

(这在直觉上是有道理的:使用的代码x不知道底层集合是不同的类型,因此它无法将代码插入到 box each 中int,或者将 each 转换int为 a long。)

在:

static void GenericMethod<T>(IEnumerable<T> sequence) where T : ISampleInterface
{
    UseInterface(sequence);
}

编译器确实知道T必须实现ISampleInterface,但这并不能阻止您定义:

public struct Foo : ISampleInterface { }

并通过了。因为没有从Footo的参考转换ISampleInterface,所以不允许协方差。

如果您告诉编译器T必须另外是引用类型,请执行以下操作:

static void GenericMethod<T>(IEnumerable<T> sequence) where T : class, ISampleInterface

然后编译器可以确定存在Tto的引用转换ISampleInterface,然后编译。

于 2019-10-10T13:25:16.673 回答