3

次のようなコードで

List<int> foo = new List<int>() { 1, 2, 3, 4, 5, 6 };
IEnumerable<int> bar = foo.Where(x => x % 2 == 1);

barSystem.Linq.Enumerable.WhereListIterator<int>遅延実行によるタイプです。実装しているため、 usingIEnumerable<int>に変換することができます。ただし、が呼び出されたときに実行されるコードの一部を特定できませんでした。私は dotPeek を逆コンパイラとして使用していますが、このようなことを試みるのはこれが初めてです。途中で間違いを犯した場合は修正してください。List<int>ToList()ToList()

これまでに見つけたことを以下に説明します (すべてのアセンブリはバージョン 4.0.0.0 です)。

  1. Enumerable.WhereArrayIterator<TSource>アセンブリ内Enumerable.csの名前空間のファイルに実装されています。クラスはそれ自体を定義することも、実装することもありません。同じファイルにあるものを実装します。実装します。System.LinqSystem.CoreToList()IEnumerable<TSource>Enumerable.Iterator<TSource>Enumerable.Iterator<TSource>IEnumerable<TSource>

  2. ToList()にもある拡張メソッドですEnumerable.cs。それが行うのは、null チェックと、List<TSource>その引数でのコンストラクターの呼び出しだけです。

  3. List<T>アセンブリ内List.csの名前空間のファイルで定義されています。によって呼び出されるコンストラクターには、シグネチャがあります。もう一度 null チェックを行い、引数を にキャストします。コレクションに要素がない場合は、空の配列の新しいリストが作成されます。それ以外の場合は、メソッドを使用して新しいリストが作成されます。System.Collections.GenericmscorlibToList()public List(IEnumerable<T> collection)ICollection<T>ICollection.CopyTo()

  4. ICollection<T>mscorlib\ System.Collections.Generic\で定義されICollection.csます。IEnumerable汎用および非汎用の形式で実装されます。

これは私が立ち往生しているところです。どちらEnumerable.WhereArrayIterator<TSource>Enumerable.Iterator<TSource>実装しないため、どこかでキャストを行う必要があり、が呼び出されたICollectionときに実行されるコードを見つけることができません。CopyTo()

4

2 に答える 2

3

これは、List<T>コンストラクター(ILSpy) の関連部分です。

ICollection<T> collection2 = collection as ICollection<T>; // this won't succeed
if (collection2 != null) 
{
    int count = collection2.Count;
    this._items = new T[count];
    collection2.CopyTo(this._items, 0);
    this._size = count;
    return;
}
// this will be used instead
this._size = 0;
this._items = new T[4];
using (IEnumerator<T> enumerator = collection.GetEnumerator())
{
    while (enumerator.MoveNext())
    {
        this.Add(enumerator.Current);
    }
}

collection as ICollection<T>;にキャストしようとすることがわかります。それICollection<T>が機能する場合は、効率的なCopyToものが使用されます。そうでない場合、シーケンスは完全に列挙されます。

YourWhereListIterator<int>はコレクションではなくクエリであるため、にキャストできないためICollection<T>、列挙されます。

于 2013-07-18T15:03:30.307 に答える
1

asオペレーターに混乱されていると思います。基本的に安全なキャストです。これはこれと同等ですが、少し高速です。

MyEndType x = null;
if (MyVarWithAs is MyEndType) x = (MyEndType)MyVarWithAs;

では、もう一度コードを見てみましょう。

 public List(IEnumerable<T> collection)
    {
      if (collection == null)
        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
      ICollection<T> collection1 = collection as ICollection<T>;
      if (collection1 != null)
      {
        int count = collection1.Count;
        if (count == 0)
        {
          this._items = List<T>._emptyArray;
        }
        else
        {
          this._items = new T[count];
          collection1.CopyTo(this._items, 0);
          this._size = count;
        }
      }
      else
      {
        this._size = 0;
        this._items = List<T>._emptyArray;
        foreach (T obj in collection)
          this.Add(obj);
      }
    }

ご覧のとおり、ifそれが であるかどうかをチェックしますnull。である場合、それは ではないnullことを意味するので、に進みます。すべてのことは、すべてをデフォルトに設定してから、すべてを手動で追加することです。(あなたの例のように)ではない渡すと、パスを通過します。ICollection<T>elseelseIEnumerable<T>ICollection<T>else

于 2013-07-18T15:09:13.897 に答える