【问题标题】:Why does casting a value as IEnumerable<T> behave differently based on how I initialized the value?为什么将值转换为 IEnumerable<T> 的行为会根据我初始化值的方式而有所不同?
【发布时间】:2016-05-31 18:25:02
【问题描述】:

我有一些代码接受一个值(对象类型)并尝试将其转换为整数和 uint 的 IEnumerable,如下所示:

var idList = value as IEnumerable<int>;
var uintList = value as IEnumerable<uint>;

当值以这种方式初始化时:

uint number = 1;
object value = new []{ number };

idList 和 uintList 都有值,但调用 idList.ToList() 会导致 ArrayTypeMismatchException。但是,当使用new List&lt;uint&gt;{ number } 生成该值时,idList 如预期的那样为空。

此外,在 VS 2015 的即时窗口中调用 var idList = value as IEnumerable&lt;int&gt;; 会返回 null,正如我所料,即使该值是使用集合初始化程序生成的。

.Net fiddle reproducing the error here.

这是怎么回事?

【问题讨论】:

  • 你可以看看这个堆栈溢出帖子:stackoverflow.com/questions/7173266/…
  • 如果我像你一样初始化value,那么var idList = value as IEnumerable&lt;int&gt;; 行会给我一个编译时错误,而不是运行时异常
  • 嗯,这里没有编译错误,但我意识到在简化代码路径时我遗漏了该值已被强制转换为对象类型,然后再被强制转换回 IEnumerable。将相应地添加到问题中,谢谢。
  • 我认为部分问题在于您正试图进行从 IEnumerable&lt;uint&gt;IEnumerable&lt;int&gt; 的隐式转换。因为这些是 IEnumerables,所以我认为它们正在被懒惰地评估。当您致电ToList 时,您会强制评估对象。另请注意,没有从 uint 到 int 的隐式转换。 uint.MaxValue 是 int.MaxValue 的两倍。 uint.MinValue 当然是零。

标签: c# casting


【解决方案1】:

我认为这是因为 C# 和 CLR 在处理 intuint 之间的转换的方式之间存在异常差异,如 answer 中所述。首先注意这段代码不会编译:

uint[] a1 = new[] { 1u };
var a2 = (int[])a1;

因为 C# 不相信存在演员表。但是,如果你走这条路:

uint[] a1 = new[] { 1u };
var a2 = (int[]) (object) a1;

运行时将决定此转换是否有效,并且它 (CLR) 有不同的想法并允许从 uint[] 转换为 int[](反之亦然),如我链接的答案中所述。

List&lt;int&gt;List&lt;uint&gt; 并非如此 - CLR 不会以特殊方式处理它们,因此不能在彼此之间转换。

因此,在您的情况下,uint[] 可以转换为 int[] 并且 int[] 实现 IEnumerable&lt;int&gt;,因此您的 idList 不为空。这不适用于列表 - 因此是您的问题。

至于为什么 ToList 在第一种情况下失败,那是因为它在内部做了类似的事情:

 uint[] a1 = new[] { 1u };
 var a2 = (int[]) (object) a1;
 // ToList copies contents to new array
 int[] copy = new int[a2.Length];
 Array.Copy(a2, copy, a2.Length);

Array.Copy 直接检查一个数组中的元素类型是否与另一个数组中的元素类型兼容。

【讨论】:

  • 这真的很奇怪,谢谢你的解释!我也不希望 CLR 和语言不同意,但是 :shrug:
猜你喜欢
  • 1970-01-01
  • 2021-04-05
  • 1970-01-01
  • 1970-01-01
  • 2017-06-11
  • 1970-01-01
  • 2021-01-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多