Valamas
Valamas

Reputation: 24759

My linq select does not work, my foreach does

I have the following LINQ Select which does not work.

Data.Select(d => d.Value.IsDirty = true); //-- Not working

My longer workaround does.

foreach (var d in Data)
    d.Value.IsDirty = true;

Why does my first code not work?

Upvotes: 2

Views: 561

Answers (3)

Marcelo Cantos
Marcelo Cantos

Reputation: 186118

Select() returns an IEnumerable<…>, which has the ability to iterate over the input and invoke the code in question, but doesn't actually do so until you enumerate it in some manner:

Data.Select(d => d.Value.IsDirty = true).ToList();

or

foreach (var _ in Data.Select(d => d.Value.IsDirty = true))
    ; // Do nothing

However, given that they perform side effects (obviously the intent here), both of the above are bad karma. Don't use them. Your original foreach is the only sensible choice.

Upvotes: 5

pnvn
pnvn

Reputation: 488

Calling Select does not cause the side effect you need, even if you force execution by iterating over the elements. If you want the side effect you have to do foreach.

For example:

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.
    }
}

Upvotes: -3

Adam Robinson
Adam Robinson

Reputation: 185703

Projection functions like Select, Where, etc. define queries. Simply calling Select does not actually do anything until the query is evaluated (almost certainly, at some point, by a foreach).

If you were to do something to force execution of the query (calling Count, for instance), you'd see it take effect.

It is, however, a bit of an abuse. These functions aren't specifically intended for state-altering operations.

Upvotes: 9

Related Questions