I\'d like one general purpose function that could be used with any Flags style enum to see if a flag exists.
This doesn\'t compile, but if anyone has a suggestion, I
I have used this before:
public static bool In<T>(this T me, T values)
where T : struct, IConvertible
{
return (me.ToInt64(null) & values.ToInt64(null)) > 0;
}
What I like about it is you can use this clean syntax to call it since in 3.5 the compiler will can infer generic parameters.
AttributeTargets a = AttributeTargets.Class;
if (a.In(AttributeTargets.Class | AttributeTargets.Module))
{
// ...
}
Well, I don't believe there is a way to do this, as there are no constraints that apply to bitwise operators.
However... you can just cast your enum to int and do it.
public static Boolean IsEnumFlagPresent(int value,int lookingForFlag)
{
return ((value & lookingForFlag) == lookingForFlag);
}
This works, but may be confusing to someone.
Question long over, but here's one for reference anyway:
public static bool HasFlag<TEnum>(this TEnum enumeratedType, TEnum value)
where TEnum : struct, IComparable, IFormattable, IConvertible
{
if (!(enumeratedType is Enum))
{
throw new InvalidOperationException("Struct is not an Enum.");
}
if (typeof(TEnum).GetCustomAttributes(
typeof(FlagsAttribute), false).Length == 0)
{
throw new InvalidOperationException("Enum must use [Flags].");
}
long enumValue = enumeratedType.ToInt64(CultureInfo.InvariantCulture);
long flagValue = value.ToInt64(CultureInfo.InvariantCulture);
if ((enumValue & flagValue) == flagValue)
{
return true;
}
return false;
}
Today, you can set the c# language version to >=7.3 and use the next code as the reference:
public static class EnumExt
{
public static IEnumerable<TEnum> Explode<TEnum>(this TEnum enumValue) where TEnum : Enum
{
var res = Enum.GetValues(enumValue.GetType())
.Cast<TEnum>()
.Where(x => enumValue.HasFlag(x));
return res;
}
public static string ExplodeToString<TEnum>(this TEnum enumValue, string delimeter = ",") where TEnum : Enum
{
return string.Join(delimeter, Explode(enumValue));
}
}
below is code that benchmarks 4 different methods. results are shown in code in comment "BENCHMARK: .. nSec".
"((enum & flag) != 0)' is 10x faster than HasFlag() function. if you are in a tight loop, then i think it is best to accept it.
public static int jumpCtr=0;
public static int ctr=0;
public static TestFlags gTestFlags = TestFlags.C;
[Flags] public enum TestFlags { A=1<<1, B=1<<2, C=1<<3 }
public static void Jump() { jumpCtr++; gTestFlags = (gTestFlags == TestFlags.B) ? TestFlags.C : TestFlags.B; }
// IsEnumFlagPresent() https://stackoverflow.com/questions/987607/c-flags-enum-generic-function-to-look-for-a-flag
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool HasFlag_Faster<T>(T value, T lookingForFlag)
where T : struct
{
int intValue = (int) (object) value;
int intLookingForFlag = (int) (object) lookingForFlag;
return ((intValue & intLookingForFlag) != 0);
}
// IsEnumFlagPresent() https://stackoverflow.com/questions/987607/c-flags-enum-generic-function-to-look-for-a-flag
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool HasFlag_Faster_Integer(int intValue, int intLookingForFlag)
{
return ((intValue & intLookingForFlag) != 0);
}
public static void Benchmark_HasFlag( )
{
if ( ! hwDvr._weAreOnGswCpu) { return; }
DateTime timer = DateTime.Now;
string a, b, c, d, e;
double base_nSecPerLoop, b_nSecPerLoop, c_nSecPerLoop, d_nSecPerLoop, e_nSecPerLoop;
int numOfLoops = (int) 1.0e6;
// ------------------------------------------------------
for (int i=0; i<numOfLoops;i++) {
Jump();
}
a = BenchMarkSystem_Helper.SimpleTimer_Loops( ref timer, numOfLoops, out base_nSecPerLoop);
// ------------------------------------------------------
// BENCHMARK: 50 nSec
for (int i=0; i<numOfLoops;i++) {
if (gTestFlags.HasFlag((TestFlags) TestFlags.C)) {
ctr++;
}
Jump();
}
b = BenchMarkSystem_Helper.SimpleTimer_Loops( ref timer, numOfLoops, out b_nSecPerLoop );
double b_diff = b_nSecPerLoop - base_nSecPerLoop;
// ------------------------------------------------------
// BENCHMARK: 3 nSec
for (int i=0; i<numOfLoops;i++) {
if ((gTestFlags & TestFlags.C) != 0) {
ctr++;
}
Jump();
}
c = BenchMarkSystem_Helper.SimpleTimer_Loops( ref timer, numOfLoops, out c_nSecPerLoop );
double c_diff = c_nSecPerLoop - base_nSecPerLoop;
// ------------------------------------------------------
// BENCHMARK: 64 nSec
for (int i=0; i<numOfLoops;i++) {
if (HasFlag_Faster<TestFlags>(value:gTestFlags, lookingForFlag: TestFlags.C)) {
ctr++;
}
Jump();
}
d = BenchMarkSystem_Helper.SimpleTimer_Loops( ref timer, numOfLoops, out d_nSecPerLoop );
double d_diff = d_nSecPerLoop - base_nSecPerLoop;
// ------------------------------------------------------
// BENCHMARK: 14 nSec
for (int i=0; i<numOfLoops;i++) {
if (HasFlag_Faster_Integer((int)gTestFlags, (int)TestFlags.C)) {
ctr++;
}
Jump();
}
e = BenchMarkSystem_Helper.SimpleTimer_Loops( ref timer, numOfLoops, out e_nSecPerLoop );
double e_diff = e_nSecPerLoop - base_nSecPerLoop;
int brkPt=0;
}