簡體   English   中英

為什么使用ToList時此Linq Cast失敗?

[英]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

消息:無法將源陣列類型分配給目標陣列類型。

我發現此異常非常特殊,因為

  1. ArrayTypeMismatchException我自己不對數組做任何事情。 這似乎是一個內部例外。
  2. Cast<sbyte>可以正常工作(如第一個示例中所示),這是在使用ToArrayToList的問題。

我的目標是.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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM