39

この不自然で些細な例を考えてみましょう。

    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);
    }

2の補数の魔法で、-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>最初の例のように)正常に動作します。使用中ToArrayまたはToList問題が発生します。

.NET v4 x86をターゲットにしていますが、3.5でも同じことが起こります。

問題を解決する方法についてのアドバイスは必要ありません。私はすでにそれを行うことができました。私が知りたいのは、なぜこの動作が最初に発生するのかということです。

編集

さらに奇妙なことに、意味のないselectステートメントを追加すると、ToListが正しく機能します。

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

1 に答える 1

31

さて、これは実際に組み合わされたいくつかの奇妙なことに依存します:

  • C#では直接にキャストすることはできませんが、CLRでは次のことが可能byte[]です。sbyte[]

    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()List<T>のコンストラクターに委任しますIEnumerable<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これで、任意の時点でaを使用しても、最終的には.になることはないため、の配列実装を使用しようとするのではなく、各要素ICollection<T>の正当な(CLRの場合)byte/変換を実行します。sbyteCopyTo

于 2012-06-14T19:04:00.877 に答える