Surendra Mourya Surendra Mourya - 3 months ago 25
C# Question

Ienumerable concat not working in for each loop

I'm trying to use the

Concat
method of an IEnumerable inside a for each loop, but I can't get it working properly.

IEnumerable<Geo> geos = null;
foreach (string a in values)
{
if (geos == null)
geos = entities.Geos.Where(g => (g.ACode == Convert.ToInt16(a)));
else
geos = geos.Concat(entities.Geos.Where(g => (g.ACode == Convert.ToInt16(a))));
}


What it returns is only values for the final "a" in values that too for the count of records present in values.

So if i have 1,2,3 as values, it return only for 3. I need the value for 1,2 and 3 as well.

Where am I going wrong?

Answer

It is likely you are using a older version of C#, in C# 5 (ships with Visual Studio 2013) they changed the behavior of foreach. In C# 4 the a in g => (g.ACode == Convert.ToInt16(a)) would be the last value of the foreach when evaluated lazely, in C# 5 and newer it will always be the current value.

To get the C# 5 behavior you just need to declare a extra varaible inside the scope of the foreach loop and use that in the capture.

IEnumerable<Geo> geos = null;
foreach (string a in values)
{
    string b = a;
    if (geos == null)
        geos = entities.Geos.Where(g => (g.ACode == Convert.ToInt16(b)));
    else
        geos = geos.Concat(entities.Geos.Where(g => (g.ACode == Convert.ToInt16(b))));
}

If you are curious the thing that changed is in C# 4 and below your original code gets translated in to

IEnumerable<Geo> geos = null;
using(IEnumerator<string> enumerator = values.GetEnumerator())
{
    string a;
    while(enumerator.MoveNext())
    {
        a = enumerator.Current;

        if (geos == null)
            geos = entities.Geos.Where(g => (g.ACode == Convert.ToInt16(a)));
        else
            geos = geos.Concat(entities.Geos.Where(g => (g.ACode == Convert.ToInt16(a))));
    }
}

In C# 5 and newer it gets translated to

IEnumerable<Geo> geos = null;
using(IEnumerator<string> enumerator = values.GetEnumerator())
{
    while(enumerator.MoveNext())
    {
        string a = enumerator.Current;

        if (geos == null)
            geos = entities.Geos.Where(g => (g.ACode == Convert.ToInt16(a)));
        else
            geos = geos.Concat(entities.Geos.Where(g => (g.ACode == Convert.ToInt16(a))));
    }
}

By doing the string b = a; in C# 4 we re-create that behavior of the declaration being inside of the while loop.