Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/279.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么使用ToList时Linq强制转换失败?_C#_Linq_Casting - Fatal编程技术网

C# 为什么使用ToList时Linq强制转换失败?

C# 为什么使用ToList时Linq强制转换失败?,c#,linq,casting,C#,Linq,Casting,考虑一下这个做作而琐碎的例子: 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.WriteLin

考虑一下这个做作而琐碎的例子:

    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);
    }
但这不起作用。我得到一个例外:

异常类型:System.ArrayTypeMismatchException

消息:无法将源阵列类型分配给目标阵列类型

我觉得这个例外很奇怪,因为

  • ArrayTypeMismatchException
    -我自己没有对数组做任何事情。这似乎是一个内部例外
  • Cast
    工作正常(如第一个示例中所示),当使用
    ToArray
    ToList
    时问题就会出现
  • 我的目标是.NETV4x86,但在3.5中也是如此

    我不需要任何关于如何解决问题的建议,我已经设法做到了。我想知道的是,为什么这种行为首先会发生

    编辑

    更奇怪的是,添加无意义的select语句会导致
    ToList
    正常工作:

    var baz = bar.Select(x => x).ToList();
    

    好吧,这真的取决于几个奇怪的结合:

    • 即使在C#中不能将
      字节[]
      直接强制转换为
      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()
      进行优化,如果它认为它不需要做任何事情(通过类似上面的
      is
      检查),它将返回原始引用-这里就是这样

    • ToList()
      委托给
      List
      的构造函数,获取
      IEnumerable

    • 该构造函数针对
      ICollection
      进行了优化,以使用
      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);
      
      objectbytes=新字节[]{246127};
      //这成功了。。。
      ICollection list=(ICollection)字节;
      sbyte[]数组=新的sbyte[2];
      list.CopyTo(数组,0);
      

    现在,如果您在任何时候使用
    Select
    ,您都不会得到
    ICollection
    ,因此它会对每个元素进行合法的(对于CLR)字节
    /
    sbyte
    转换,而不是尝试使用
    CopyTo

    的数组实现,结果是
    Select
    {-10127}
    这里有一个铸造问题。肯定有有趣的错误消息。@Lieven是的,我收集了这么多,为什么
    选择(x=>x)
    before
    ToList
    更正它?这是一个毫无意义的投影,因为同样的东西被投影回来了。我有一个解释……写出来只是花了一点时间。问得好。@vcsjones:因为这样数组帮助器就很可能不再使用了-使用
    Select
    你正在投影到
    IEnumerable
    +1个好问题。我喜欢涉及有趣边缘情况的问题。是的,我注意到运行时条形图的值类型是byte[],而不是System.Linq.Enumerable.CastIterator。谢谢你的解释!在阅读了问答之后,这是不是意味着。ToList需要用于类型安全转换?@Turbot:我不理解你的评论。你能重新表述一下吗?嗯,现在我明白了。
    Cast
    在第一个或第二个示例中都没有做任何事情,而是转换是通过将其添加到列表和CLR处理转换来处理的。@JonSkeet Oops,这与类型安全转换无关。它只是与C#编译器和CLR处理转换不同的处理方式?
    object bytes = new byte[] { 246, 127 };
    
    // This succeeds...
    ICollection<sbyte> list = (ICollection<sbyte>) bytes;
    
    sbyte[] array = new sbyte[2];
    
    list.CopyTo(array, 0);