不足しているZip
機能について尋ねる別の質問に触発されました:
クラスにForEach
拡張メソッドがないのはなぜEnumerable
ですか?またはどこか?ForEach
メソッドを取得する唯一のクラスはList<>
です。それが欠落している(パフォーマンス)理由はありますか?
Parallel.ForEach
ためEnumerable.ForEach
だけにスワップを試み ます。C#は、ここで物事を簡単にするためのトリックを逃しました。
不足しているZip
機能について尋ねる別の質問に触発されました:
クラスにForEach
拡張メソッドがないのはなぜEnumerable
ですか?またはどこか?ForEach
メソッドを取得する唯一のクラスはList<>
です。それが欠落している(パフォーマンス)理由はありますか?
Parallel.ForEach
ためEnumerable.ForEach
だけにスワップを試み ます。C#は、ここで物事を簡単にするためのトリックを逃しました。
回答:
ほとんどの場合、この作業を行う言語には、foreachステートメントが既に含まれています。
私は以下を見ることを嫌います:
list.ForEach( item =>
{
item.DoSomething();
} );
の代わりに:
foreach(Item item in list)
{
item.DoSomething();
}
後者は、ほとんどの状況でより明確で読みやすくなりますが、タイプするのが少し長くなる可能性があります。
しかし、私はその問題に対する私のスタンスを変更したことを認めなければなりません。ForEach()拡張メソッドは、いくつかの状況で実際に役立ちます。
ステートメントとメソッドの主な違いは次のとおりです。
これらはすべて、多くの人々によってここで作成された素晴らしい点であり、人々が機能を欠いている理由を私は見ることができます。Microsoftが次のフレームワークの反復で標準のForEachメソッドを追加してもかまいません。
foreach
enumerableがパラメーター化されている場合、コンパイル時に型チェックされます。架空のForEach
拡張メソッドとは異なり、非ジェネリックコレクションのコンパイル時の型チェックだけが欠けています。
col.Where(...).OrderBy(...).ForEach(...)
。構文がはるかに単純になり、冗長なローカル変数やforeach()の長いブラケットによる画面の汚染がなくなりました。
list.ForEach(item => item.DoSomething())
。そして、それはリストだと誰が言うのですか?明らかなユースケースはチェーンの最後です。foreachステートメントでは、チェーン全体をの後ろに配置する必要がありin
、ブロック内で実行される操作ははるかに自然または一貫性が低くなります。
ForEachメソッドはLINQの前に追加されました。ForEach拡張機能を追加した場合、拡張メソッドの制約により、Listインスタンスに対して呼び出されることはありません。追加されなかったのは、既存のものと干渉しないためだと思います。
ただし、この小さな便利な機能を見逃した場合は、独自のバージョンをロールアウトできます
public static void ForEach<T>(
this IEnumerable<T> source,
Action<T> action)
{
foreach (T element in source)
action(element);
}
この拡張メソッドを書くことができます:
// Possibly call this "Do"
IEnumerable<T> Apply<T> (this IEnumerable<T> source, Action<T> action)
{
foreach (var e in source)
{
action(e);
yield return e;
}
}
長所
連鎖が可能:
MySequence
.Apply(...)
.Apply(...)
.Apply(...);
短所
反復を強制するために何かをするまで、実際には何もしません。そのため、呼び出さないでください.ForEach()
。あなたは書くことができます.ToList()
最後に、またはあなたも、この拡張メソッドを書くことができます:
// possibly call this "Realize"
IEnumerable<T> Done<T> (this IEnumerable<T> source)
{
foreach (var e in source)
{
// do nothing
;
}
return source;
}
これは、出荷されているC#ライブラリからの逸脱が大きすぎる可能性があります。あなたの拡張メソッドに慣れていない読者は、あなたのコードをどうするかを知らないでしょう。
{foreach (var e in source) {action(e);} return source;}
numbers.Select(n => n*2);
Select()
各要素に関数を適用して関数の値を返す言うApply()
適用言うAction
各要素および戻り元の要素。
Select(e => { action(e); return e; })
ここでの議論は答えを与えます:
実際、私が目撃した具体的な議論は、実際には機能の純粋さにかかっていました。式の中には、副作用がないことを前提とすることがよくあります。ForEachを使用すると、副作用を我慢するだけでなく、特に副作用が発生します。-キース・ファーマー(パートナー)
基本的に、拡張メソッドを機能的に「純粋」に保つことを決定しました。ForEachは、意図しないEnumerable拡張メソッドを使用するときに副作用を助長します。
foreach
ほとんどの場合、組み込みの構成を使用する方がよいことに同意しますが、このバリエーションをForEach <>拡張で使用する方が、通常のインデックスをforeach
自分で管理する必要がある場合よりも少し優れています。
public static int ForEach<T>(this IEnumerable<T> list, Action<int, T> action)
{
if (action == null) throw new ArgumentNullException("action");
var index = 0;
foreach (var elem in list)
action(index++, elem);
return index;
}
例
var people = new[] { "Moe", "Curly", "Larry" };
people.ForEach((i, p) => Console.WriteLine("Person #{0} is {1}", i, p));
あなたに与えるでしょう:
Person #0 is Moe
Person #1 is Curly
Person #2 is Larry
回避策の1つは、を記述すること.ToList().ForEach(x => ...)
です。
長所
理解しやすい-読者はC#に同梱されるものを知るだけでよく、追加の拡張メソッドは必要ありません。
構文上のノイズは非常に穏やかです(わずかなコードを追加するだけです)。
.ForEach()
とにかくネイティブはコレクション全体を実現する必要があるため、通常は追加のメモリは必要ありません。
短所
操作の順序は理想的ではありません。1つの要素に気づき、それに基づいて行動し、繰り返します。このコードは最初にすべての要素を認識し、次に順番にそれらに作用します。
リストを実現すると例外がスローされる場合、単一の要素を操作することはできません。
列挙が(自然数のように)無限である場合、あなたは運が悪いです。
Enumerable.ForEach<T>
方法はないが方法はあると前もって述べていれば、この応答はより明確になりますList<T>.ForEach
。c)「とにかく、ネイティブの.ForEach()がコレクション全体を実現する必要があるため、通常、追加のメモリは必要ありません。」-完全でまったくナンセンス。ここではそれがなかった場合はC#を提供することをEnumerable.ForEach <T>の実装は次のとおりです。public static void ForEach<T>(this IEnumerable<T> list, Action<T> action) { foreach (T item in list) action(item); }
私はいつも自分自身と思っていました。そのため、私はいつもこれを携帯しています。
public static void ForEach<T>(this IEnumerable<T> col, Action<T> action)
{
if (action == null)
{
throw new ArgumentNullException("action");
}
foreach (var item in col)
{
action(item);
}
}
素敵な小さな拡張メソッド。
そのため、LINQ拡張メソッドのように値を返さないため、ForEach拡張メソッドは適切ではないという事実について多くのコメントがありました。これは事実ですが、完全に真実ではありません。
LINQ拡張メソッドはすべて値を返すため、これらを一緒にチェーンできます。
collection.Where(i => i.Name = "hello").Select(i => i.FullName);
ただし、LINQが拡張メソッドを使用して実装されているからといって、拡張メソッドを同じ方法で使用して値を返す必要があるという意味ではありません。値を返さない一般的な機能を公開する拡張メソッドを作成することは、完全に有効な使用法です。
ForEachについての具体的な議論は、拡張メソッドの制約に基づいて(つまり、拡張メソッドが同じシグネチャで継承されたメソッドをオーバーライドすることは決してない)、カスタム要素拡張メソッドがimpelementであるすべてのクラスで使用できる場合があるということです。 IEnumerable >リストを除く>。これにより、拡張メソッドまたは継承メソッドが呼び出されているかどうかによって、メソッドの動作が異なる場合に混乱が生じる可能性があります。<T
<T
(連鎖可能ですが、遅延評価されます)を使用してSelect
、最初に操作を実行してから、アイデンティティ(または必要に応じて何か)を返すことができます
IEnumerable<string> people = new List<string>(){"alica", "bob", "john", "pete"};
people.Select(p => { Console.WriteLine(p); return p; });
Count()
(afaikを列挙するための最も安価な操作)またはとにかく必要な別の操作のいずれかで、それがまだ評価されていることを確認する必要があります。
私はそれが標準ライブラリに取り入れられるのを見たいです:
static IEnumerable<T> WithLazySideEffect(this IEnumerable<T> src, Action<T> action) {
return src.Select(i => { action(i); return i; } );
}
上記のコードはpeople.WithLazySideEffect(p => Console.WriteLine(p))
、foreachと実質的に同等になりますが、レイジーでチェーン可能になります。
Select
はもうやるべきことをやらない。これは間違いなくOPが求めるものに対する解決策ですが、トピックの読みやすさに関しては、selectが関数を実行することを誰も期待していません。
Select
それはの実装に問題があります行うことになっています何をしないSelect
ではないコードと、その通話Select
何に対して何ら影響ありません、Select
ありませんが。
MoreLINQ NuGetは、ForEach
探している拡張メソッド(Pipe
およびデリゲートを実行してその結果を生成するメソッド)を提供することに注意してください。見る:
@Coincoin
foreach拡張メソッドの真の力は、Action<>
コードに不要なメソッドを追加せずにを再利用できることです。10個のリストがあり、それらに対して同じロジックを実行したいとします。対応する関数はクラスに適合せず、再利用されません。10のforループや、明らかに属していないヘルパーであるジェネリック関数を使用する代わりに、すべてのロジックを1か所に保持できます(Action<>
したがって、数十行が
Action<blah,blah> f = { foo };
List1.ForEach(p => f(p))
List2.ForEach(p => f(p))
等...
ロジックは1か所にあり、クラスを汚染していません。
f(p)
は{ }
、省略形のを省略しますfor (var p in List1.Concat(List2).Concat(List2)) f(p);
。
ほとんどのLINQ拡張メソッドは結果を返します。ForEachは何も返さないため、このパターンに適合しません。
public IEnumerable<T> Foreach<T>(this IEnumerable<T> items, Action<T> action) { /* error check */ foreach (var item in items) { action(item); yield return item; } }
部分的には、言語デザイナーが哲学的観点からそれに同意しないためです。
https://blogs.msdn.microsoft.com/ericlippert/2009/05/18/foreach-vs-foreach/
selectは、何かを返したいときに使用できます。そうでない場合は、コレクション内の何も変更したくないので、最初にToListを使用できます。
私はそれについてブログ投稿を書きました:http : //blogs.msdn.com/kirillosenkov/archive/2009/01/31/foreach.aspx
このメソッドを.NET 4.0で確認したい場合は、こちらから投票できます。http: //connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID = 279093
3.5では、IEnumerableに追加されたすべての拡張メソッドがLINQサポートのために用意されています(これらはSystem.Linq.Enumerableクラスで定義されていることに注意してください)。この投稿では、なぜforeachがLINQに属さないのかを説明 します。Parallel.Forに似た既存のLINQ拡張メソッドですか?
それは私ですか、それともList <T>ですか。Foreachは、Linqによってほとんど廃止されています。もともとあった
foreach(X x in Y)
ここで、YはIEnumerable(2.0以前)でなければならず、GetEnumerator()を実装する必要がありました。生成されたMSILを見ると、次のようにまったく同じであることがわかります。
IEnumerator<int> enumerator = list.GetEnumerator();
while (enumerator.MoveNext())
{
int i = enumerator.Current;
Console.WriteLine(i);
}
(MSIL についてはhttp://alski.net/post/0a-for-foreach-forFirst-forLast0a-0a-.aspxを参照してください)
それからDotNet2.0でジェネリックスとリストが登場しました。Foreachは常にVistorパターンの実装であると感じていました(Gamma、Helm、Johnson、VlissidesによるDesign Patternsを参照)。
もちろん、3.5ではもちろん、代わりにLambdaを使用して同じ効果を得ることができます。例として、http://dotnet-developments.blogs.techtarget.com/2008/09/02/iterators-lambda-and-linq-oh-を試してください。 俺の/
ForEach <T>の結果、foreachキーワードが実行時にチェックされるコンパイル時の型チェックが行われることを誰も指摘していません。
コードで両方の方法が使用されているリファクタリングをいくつか行った後、私は.ForEachを支持します。これは、foreachの問題を見つけるためにテストの失敗/ランタイムの失敗を突き止める必要があったためです。
foreach
コンパイル時間のチェックが少なくなっていることがわかりません。もちろん、コレクションが非ジェネリックIEnumerableの場合、ループ変数はにobject
なりますが、仮想のForEach
拡張メソッドについても同じことが言えます。