【问题标题】:Cast Exception when performing LINQ on IEnumerable在 IEnumerable 上执行 LINQ 时出现强制转换异常
【发布时间】:2013-05-01 14:11:29
【问题描述】:

假设我有两个班级,

class A
{
}

class B : A
{
}

我有一个方法接受foo 类型的参数IEnumerable<A>;

void AMethod(IEnumerable<A> foo)
{
}

而是传入IEnumerable&lt;B&gt;类型的值。

AMethod(new[] { new B() });

这会编译并执行,尽管在执行时 foo 已隐式转换为 IEnumerable&lt;B&gt;。现在假设我的 IEnumerable&lt;B&gt; 包含 A 类型的对象(我认为它们是混合的还是相同的并不重要)。当我打电话给foo.Any() 时,我得到了一个例外:

无法将“A”类型的对象转换为“B”类型

我知道我不能将基类转换为子类,但这不是我想要做的(事实上,在执行的这一点上,我什至不在乎它是什么类型)。我猜 LINQ 本质上是在尝试进行这种转换,可能是基于fooIEnumerable&lt;B&gt; 类型这一事实。因此,似乎我需要编写两种单独的方法,一种处理IEnumerable&lt;A&gt;,另一种处理IEnumerable&lt;B&gt;。我不明白为什么我需要这样做。有什么想法吗?

编辑:

正在进行一些动态转换和转换,设法吐出一个充满“A”的IEnumerable&lt;B&gt;,直到现在我认为这也是不可能的。我会尽力翻译导致此方法调用发生的情况:

protected void SetDynamicData(dynamic data)
{
  _data = data;
  IsB = typeof(IBInterface).IsAssignableFrom(_data.DataType);
}

...

var foo = IsB ? _data.Cast<B>() : data.Cast<A>();
return BuildJqGridData<A, B, int>(gridModel, foo);

【问题讨论】:

  • 如果 B 继承了 A,则 B 是 A,但 A 不是 B。
  • IEnumerable&lt;B&gt; 如何包含A 类型的对象?能发个小代码sn-p来演示这个问题吗?
  • 我已经更新了你的问题,但没有改变其含义以使其更具可读性。
  • 你的例子和你的问题不一样。在您的示例中,您传递了一个带有B 类型项目的IEnumerable&lt;B&gt;。这将工作
  • _data是什么类型?

标签: linq types casting ienumerable any


【解决方案1】:

IEnumerable&lt;B&gt; 不能包含 A 类型的对象,因为 A 不是 B

我可以写这段代码,

IEnumerable<B> dodgy = (new[] { new A() }).Cast<B>();

它会编译,尽管显然是错误的。编译器假设我知道我在做什么。请记住,IEnumerable 序列中的任何项目尚未被评估。

当我编写评估dodgy 成员的代码时,我得到了异常,因为A 不是B 并且不支持转换为B

我会写

IEnumerable<A> fine = new[] { new B() };

不需要演员表,一切正常,因为BA


如果我这样做,

var hungrilyDodgy = (new[] { new A() }).Cast<B>().ToList();

Tolist() 将强制枚举和评估IEnumerable,因此会更快地抛出异常。

【讨论】:

  • 我认为这就是我所看到的。看来我正在使用的代码正在采取一种非常迂回的方式来完成你所拥有的,使用条件来决定它的类型。不知何故,我让它选择不正确。只是为了确认一下,当您在运行时使用它时,您可以成功创建“狡猾”并传递它,您就不能用它做任何事情吗?如果是这样,你就得到了正确的答案(感谢)。
  • @user2339577,没错,在枚举IEnumerable 之前不会进行评估。编译器只知道Cast&lt;&gt;() 返回一个兼容的类型。在您的情况下,它失败并引发异常。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-02
相关资源
最近更新 更多