Linq や Lambda ステートメントを使用せずに C# を記述することに慣れていますが、理解を深めたいと考えています。foreach
ループを使用して C# 2.0 で記述された次のようなコードがあります。
List<string> strings = new List<string>();
strings.Add("1");
strings.Add("blah");
List<int> ints1 = new List<int>();
foreach (string x in strings)
{
int r;
if (int.TryParse(x, out r))
ints1.Add(r);
}
文字列のリストから int のリストを生成し、実際には int でないものは無視するという単純なタスクを実行しています。私の限られた経験では、Linq と Lambda ステートメントは foreach ステートメントを非常に簡潔で読みやすい方法に切り詰めて、同じことを行うことができるようです。そこで、C# 3.0 を使ってこの小さなものを試してみようと思いました。しかし、私が思いつくことができる最高のものはこれです:
IEnumerable<int> ints2 = strings.Select(x =>
{
int r;
if (int.TryParse(x, out r))
return r as int?;
return null;
})
.Where<int?>(x => x != null)
.Select(x => x.Value);
うん!変換とフィルタリングを 1 回の呼び出しで組み合わせる方法を見つけることができず、元のものよりもはるかに悪いように見えるものになってしまいました。これを行う方法はありますか、それとも foreach に固執する必要がありますか?
編集:調査結果を要約すると、.NET 4.0 を使用している場合に LINQ でこれを行う 2 つの方法があります。
IEnumerable<int> ints1 = strings
.Where(x => new Int32Converter().IsValid(x))
.Select(x => int.Parse(x));//Broken in .NET 3.5 due to bug in Int32Converter
IEnumerable<int> int2 = strings
.Where(x => { int r; return int.TryParse(x, out r); })
.Select(x => int.Parse(x));
2 番目の方法は高速であり、.NET 3.5 では壊れていません。そして、foreach の代わりに、受け入れられた回答に従って、これを拡張メソッド内に配置しない理由はおそらくないでしょう。バグについては接続の問題を参照してください。Int32Converter