Select
動作しない次の LINQがあります。
Data.Select(d => d.Value.IsDirty = true); //-- Not working
私のより長い回避策はそうです。
foreach (var d in Data)
d.Value.IsDirty = true;
最初のコードが機能しないのはなぜですか?
Select
、 などの射影関数はクエリWhere
を定義します。単に呼び出すだけでは、クエリが評価されるまで実際には何もしません(ほぼ確実に、ある時点で a によって)。Select
foreach
クエリの実行を強制するために何かを行う場合 (Count
たとえば、 を呼び出す)、それが有効になることがわかります。
ただし、これは少し乱用です。これらの関数は、状態変更操作を特に意図したものではありません。
Select()
を返しますIEnumerable<…>
。これには、入力を反復処理して問題のコードを呼び出す機能がありますが、何らかの方法で列挙するまで実際にはそうしません。
Data.Select(d => d.Value.IsDirty = true).ToList();
また
foreach (var _ in Data.Select(d => d.Value.IsDirty = true))
; // Do nothing
ただし、副作用を実行することを考えると (明らかにここでの意図)、上記の両方が悪いカルマです。それらを使用しないでください。あなたのオリジナルforeach
が唯一の賢明な選択です。
要素を繰り返し処理して実行を強制しても、呼び出しSelect
によって必要な副作用は発生しません。副作用が必要な場合は、実行する必要がありますforeach
。
例えば:
class MyValue
{
public MyValue(bool flag) { Flag = flag; }
public bool Flag { get; set; }
}
class MyValueContainer
{
public MyValueContainer(MyValue val) { MyVal = val; }
public MyValue MyVal { get; set; }
}
class Program
{
static void Main(string[] args)
{
var someList = new List<MyValueContainer>();
someList.Add(new MyValueContainer(new MyValue(true)));
someList.Add(new MyValueContainer(new MyValue(true)));
someList.Add(new MyValueContainer(new MyValue(false)));
someList.Add(new MyValueContainer(new MyValue(true)));
var trueCount = someList.Count(x => x.MyVal.Flag); // 3
var falseCount = someList.Count(x => !x.MyVal.Flag); // 1
// try causing side effect by calling Select
someList.Select(x => x.MyVal.Flag = false);
// force execution. call Count
trueCount = someList.Count(x => x.MyVal.Flag); // still 3... no side effect.
falseCount = someList.Count(x => !x.MyVal.Flag); // still 1... no side effect.
foreach (var x in someList)
x.MyVal.Flag = false;
trueCount = someList.Count(x => x.MyVal.Flag); // 0... side effect seen.
falseCount = someList.Count(x => !x.MyVal.Flag); // 4... side effect seen.
}
}