![](/img/trans.png)
[英]Why does this fail when I don't use the ToList method in a for loop?
[英]Why does this Linq Cast Fail when using ToList?
考慮一下這個人為的,瑣碎的例子:
var foo = new byte[] {246, 127};
var bar = foo.Cast<sbyte>();
var baz = new List<sbyte>();
foreach (var sb in bar)
{
baz.Add(sb);
}
foreach (var sb in baz)
{
Console.WriteLine(sb);
}
借助Twos Complement的魔力,-10和127將被打印到控制台上。 到目前為止,一切都很好。 敏銳的眼睛會看到我正在遍歷一個枚舉並將其添加到列表中。 聽起來像ToList
:
var foo = new byte[] {246, 127};
var bar = foo.Cast<sbyte>();
var baz = bar.ToList();
//Nothing to see here
foreach (var sb in baz)
{
Console.WriteLine(sb);
}
除非那行不通。 我得到這個例外:
異常類型:System.ArrayTypeMismatchException
消息:無法將源陣列類型分配給目標陣列類型。
我發現此異常非常特殊,因為
ArrayTypeMismatchException
我自己不對數組做任何事情。 這似乎是一個內部例外。 Cast<sbyte>
可以正常工作(如第一個示例中所示),這是在使用ToArray
或ToList
的問題。 我的目標是.NET v4 x86,但在3.5中也會發生同樣的情況。
我不需要任何解決問題的建議,我已經設法做到了。 我想知道的是為什么這種行為首先發生?
編輯 :
甚至很奇怪,添加無意義的select語句也會導致ToList
正常工作:
var baz = bar.Select(x => x).ToList();
好的,這實際上取決於幾個奇怪的因素:
即使在C#中,您不能直接將byte[]
sbyte[]
轉換為sbyte[]
,但CLR允許:
var foo = new byte[] {246, 127}; // This produces a warning at compile-time, and the C# compiler "optimizes" // to the constant "false" Console.WriteLine(foo is sbyte[]); object x = foo; // Using object fools the C# compiler into really consulting the CLR... which // allows the conversion, so this prints True Console.WriteLine(x is sbyte[]);
Cast<T>()
進行了優化,如果它認為不需要執行任何操作(通過上述的is
檢查),它將返回原始引用-就是這種情況。
ToList()
委托IEnumerable<T>
的List<T>
的構造方法
該構造函數已針對ICollection<T>
進行了優化,以使用CopyTo
..., 這就是失敗的原因。 這是一個版本,除了CopyTo
之外,沒有其他方法可以調用:
object bytes = new byte[] { 246, 127 }; // This succeeds... ICollection<sbyte> list = (ICollection<sbyte>) bytes; sbyte[] array = new sbyte[2]; list.CopyTo(array, 0);
現在,如果您使用的是Select
在任何時候,你不會有結束ICollection<T>
所以經過合法的(為CLR) byte
/ sbyte
轉換為每個元素,而不是試圖用數組實現的CopyTo
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.