C# 铸造一个系列<;T>;到接口-为什么不';它不起作用吗?

C# 铸造一个系列<;T>;到接口-为什么不';它不起作用吗?,c#,collections,casting,C#,Collections,Casting,有人能解释一下为什么下面的代码会引发以下异常: InvalidCastException:无法将类型为“System.Collections.ObjectModel.Collection'1[UserQuery+Test]”的对象强制转换为类型为“System.Collections.ObjectModel.Collection'1[UserQuery+ITest]”。 public interface ITest { } public class Test : ITest { } void

有人能解释一下为什么下面的代码会引发以下异常:

InvalidCastException:无法将类型为“System.Collections.ObjectModel.Collection'1[UserQuery+Test]”的对象强制转换为类型为“System.Collections.ObjectModel.Collection'1[UserQuery+ITest]”。

public interface ITest
{
}

public class Test : ITest
{
}

void Main()
{
  Collection<Test> t = new Collection<Test>();
  t.Add(new UserQuery.Test());
  var casted = (Collection<ITest>)t.Cast<ITest>();
}
公共接口测试
{
}
公共类考试:ITest
{
}
void Main()
{
集合t=新集合();
t、 添加(newuserquery.Test());
var casted=(集合)t.Cast();
}

Cast
的签名意味着输出了
T
,但它不是。发生了什么事?协方差与此有关吗?

当您使用
Enumerable.Cast
时,您正在创建一个新的
IEnumerable
,而不仅仅是传统意义上的“Cast”


因此,返回的集合不再是
集合
,而是
IEnumerable
的内部(非公共)实现。当您使用
Enumerable.Cast时,您正在创建一个新的
IEnumerable
,而不仅仅是传统意义上的“casting”

因此,返回的集合不再是
集合
,而是
IEnumerable
强制转换的内部(非公共)实现。 您可以创建一个集合,这样就不需要强制转换:

void Main()
{
  Collection<ITest> t = new Collection<ITest>();
  t.Add(new UserQuery.Test());
}
void Main()
{
集合t=新集合();
t、 添加(newuserquery.Test());
}
不需要铸造。 您可以创建一个集合,这样就不需要强制转换:

void Main()
{
  Collection<ITest> t = new Collection<ITest>();
  t.Add(new UserQuery.Test());
}
void Main()
{
集合t=新集合();
t、 添加(newuserquery.Test());
}

好吧,它可能会也可能不会创建一个新的IEnumerable
。如果不需要的话,它会优化为不需要。请参阅@JonSkeet Very true-但更安全的做法是假设它不会与您传入的集合类型相同…更安全的做法是假设两者都可能发生-对结果的操作可能会影响源或不影响源,因此,任何一种方法都有可能导致错误的假设。@JonHanna假设您必须将其视为
IEnumerable
会导致错误的假设吗?如果假设它的
IEnumerable
,则将其用作只读/枚举,这应该是这里更安全的假设。。。(考虑到该接口,无法对集合进行操作。)@Reed我不会做任何假设。假设它是一个不同的集合,如果你认为你可以枚举它并更改集合,那么它会咬你一口,因为如果它是同一个集合,你在尝试时会得到一个异常。好吧,它可能会也可能不会创建一个
新的IEnumerable
。如果不需要的话,它会优化为不需要。请参阅@JonSkeet Very true-但更安全的做法是假设它不会与您传入的集合类型相同…更安全的做法是假设两者都可能发生-对结果的操作可能会影响源或不影响源,因此,任何一种方法都有可能导致错误的假设。@JonHanna假设您必须将其视为
IEnumerable
会导致错误的假设吗?如果假设它的
IEnumerable
,则将其用作只读/枚举,这应该是这里更安全的假设。。。(考虑到该接口,无法对集合进行操作。)@Reed我不会做任何假设。假设它是一个不同的集合,如果您认为可以对它进行枚举并更改该集合,则会对您造成不利影响,因为如果它是同一个集合,则在尝试该操作时会出现异常。