したがって、Find()
は_List<T>
_メソッドのみであるのに対して、First()
は_IEnumerable<T>
_の拡張機能であることがわかります。パラメータが渡されない場合、First()
は最初の要素を返し、Find()
は例外をスローすることもわかっています。最後に、要素が見つからない場合はFirst()
が例外をスローし、Find()
は型のデフォルト値を返すことを知っています。
これで、私が実際に求めていることについての混乱が解消されることを願っています。これはコンピューターサイエンスの質問であり、これらの方法を計算レベルで扱います。 _IEnumerable<T>
_拡張機能は、内部で期待されるように常に動作するとは限らないことを理解しました。 Qがあります。「金属に近い」という観点から言うと、Find()
とFirst()
の違いは何ですか?
この質問に対応するための基本的な前提を提供するコードを次に示します。
_var l = new List<int> { 1, 2, 3, 4, 5 };
var x = l.First(i => i == 3);
var y = l.Find(i => i == 3);
_
First()
とFind()
が上記のコードで値を検出する方法に実際の計算上の違いはありますか?
注:現時点では、AsParallel()
やAsQueryable()
などを無視しましょう。
List<T>.Find
のコードは次のとおりです(Reflectorから)。
public T Find(Predicate<T> match)
{
if (match == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
}
for (int i = 0; i < this._size; i++)
{
if (match(this._items[i]))
{
return this._items[i];
}
}
return default(T);
}
そして、ここにEnumerable.First
があります:
public static TSource First<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
if (predicate == null)
{
throw Error.ArgumentNull("predicate");
}
foreach (TSource local in source)
{
if (predicate(local))
{
return local;
}
}
throw Error.NoMatch();
}
したがって、どちらの方法もほぼ同じように機能します。つまり、述語に一致するものが見つかるまですべての項目を繰り返します。唯一の顕著な違いは、Find
は要素数を既に知っているためfor
ループを使用し、First
はそれを知らないためforeachループを使用することです。
First
は何も見つからなかった場合に例外をスローしますが、FirstOrDefault
はFind
とまったく同じように動作します(要素を反復処理する方法は別として)。
BTW FindはFirstOrDefault()
ではなくFirst()
と同等です。 First()
の述語がリスト要素に満足していない場合、例外が発生するためです。ここでは dotpeek を返します。これは、ReSharperの機能のいくつかを備えた別の優れた無料のリフレクターの代替品です
Enumerable.First(...)
およびEnumerable.FirstOrDefault(...)
拡張メソッドの場合:
public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) {
if (source == null) throw Error.ArgumentNull("source");
if (predicate == null) throw Error.ArgumentNull("predicate");
foreach (TSource element in source) {
if (predicate(element)) return element;
}
return default(TSource);
}
public static TSource First<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) {
if (source == null) throw Error.ArgumentNull("source");
if (predicate == null) throw Error.ArgumentNull("predicate");
foreach (TSource element in source) {
if (predicate(element)) return element;
}
throw Error.NoMatch();
}
list <>。Findの場合:
/// <summary>
/// Searches for an element that matches the conditions defined by the specified predicate, and returns the first occurrence within the entire <see cref="T:System.Collections.Generic.List`1"/>.
/// </summary>
///
/// <returns>
/// The first element that matches the conditions defined by the specified predicate, if found; otherwise, the default value for type <paramref name="T"/>.
/// </returns>
/// <param name="match">The <see cref="T:System.Predicate`1"/> delegate that defines the conditions of the element to search for.</param><exception cref="T:System.ArgumentNullException"><paramref name="match"/> is null.</exception>
[__DynamicallyInvokable]
public T Find(Predicate<T> match)
{
if (match == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
for (int index = 0; index < this._size; ++index)
{
if (match(this._items[index]))
return this._items[index];
}
return default (T);
}
List<>
はどのような方法でも索引付けされていません。特定の値を見つけるには、すべての値を調べる必要があります。したがって、列挙可能なヘルパーオブジェクトインスタンスの作成を除き、列挙可能なリストを介してリストを走査する場合と比べて、大きな違いはありません。
とはいえ、Find
関数はFirst
拡張メソッド(Framework V2.0 vs. V3.5)よりもずっと前に作成されたものであり、Find
if List<>
クラスは、拡張メソッドと同時に実装されていました。
1- Find()
は、エンティティがコンテキストにない場合にNull
を返しますが、First()
は例外をスローします
2- Find()
は、コンテキストに追加されたが、まだデータベースに保存されていないエンティティを返します