Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use linq to check if an flags/bitwise enumeration contains a type?

the following lambda statemement returns null, when i was hoping it would return a string value.

var countryCode = AddressComponents
    .Where(x => x.AddressType == AddressType.Country)
    .Select(x => x.ShortName)
    .SingleOrDefault();

now the AddressType property of the current instance i'm interrigating contains the following data:

AddressType.Political | AddressType.Country

so it's containing TWO values.

Of course, my lambda will not work, because the value of country (lets assume it's 1) != the value of Political bitwise or Country (lets assume it's 1 | 2 == 3).

Any ideas?

I'm worried i need to have something really fraking ugly like ...

((AddressTypes & AddressType.Country) == AddressType.Country)

.. thoughts?

like image 914
Pure.Krome Avatar asked Oct 07 '10 05:10

Pure.Krome


2 Answers

.NET 4.0 has theEnum.HasFlagmethod:

x => x.AddressType.HasFlag(AddressType.Country)

If you are not on .NET 4.0, the bitwiseANDyou have there is a good choice. If you don't like the pattern, check out UnconstrainedMelody, which has an extension method for this purpose. Alternatively, you can write one yourself; this question will probably be of help - Anyone know a good workaround for the lack of an enum generic constraint?

like image 198
Ani Avatar answered Oct 19 '22 22:10

Ani


I urge caution with Enum.HasFlag in .NET 4.0. When I profiled my compute-bound app, using ANTS 6.0, this function came up near the top. Going back to the old manual bit flag testing gave a factor of >100 speedup in my case. Until this BCL bug is worked out, consider yourself advised:

using System;
using System.Diagnostics;

class Program
{
    [Flags] enum test { flag1 = 1, flag2 = 2, flag4 = 4 }

    static void Main(string[] args)
    {
        Stopwatch s;
        test t = test.flag4;

        s = Stopwatch.StartNew();
        for (int c=0,i=0; i < 50000000; i++)
            if (t.HasFlag(test.flag2))
                c++;
        Console.WriteLine(s.ElapsedMilliseconds);   // 22837 ms.

        s = Stopwatch.StartNew();
        for (int c=0,i=0; i < 50000000; i++)
            if ((t & test.flag2) > 0)
                c++;
        Console.WriteLine(s.ElapsedMilliseconds);   // 172 ms.
    }
}
like image 39
Glenn Slayden Avatar answered Oct 19 '22 22:10

Glenn Slayden