我想要一个可以与任何Flags样式枚举一起使用的通用函数来查看是否存在标志。
这不能编译,但如果有人有建议,我会很感激。
public static Boolean IsEnumFlagPresent<T>(T value,T lookingForFlag)
where T:enum
{
Boolean result = ((value & lookingForFlag) == lookingForFlag);
return result ;
}
答案 0 :(得分:21)
您是否希望用包含一行代码的函数替换一行代码?我要说只使用一行代码......
答案 1 :(得分:20)
不,你不能用C#泛型做到这一点。但是,你可以做:
public static bool IsEnumFlagPresent<T>(T value, T lookingForFlag)
where T : struct
{
int intValue = (int) (object) value;
int intLookingForFlag = (int) (object) lookingForFlag;
return ((intValue & intLookingForFlag) == intLookingForFlag);
}
这仅适用于基础类型为int
的枚举,并且它的效率有点低,因为它会将值设置为...但它应该有效。
您可能想要添加执行类型检查,确认T实际上是枚举类型(例如typeof(T).BaseType == typeof(Enum)
)
这是一个完整的程序,证明它有效:
using System;
[Flags]
enum Foo
{
A = 1,
B = 2,
C = 4,
D = 8
}
class Test
{
public static Boolean IsEnumFlagPresent<T>(T value, T lookingForFlag)
where T : struct
{
int intValue = (int) (object) value;
int intLookingForFlag = (int) (object) lookingForFlag;
return ((intValue & intLookingForFlag) == intLookingForFlag);
}
static void Main()
{
Console.WriteLine(IsEnumFlagPresent(Foo.B | Foo.C, Foo.A));
Console.WriteLine(IsEnumFlagPresent(Foo.B | Foo.C, Foo.B));
Console.WriteLine(IsEnumFlagPresent(Foo.B | Foo.C, Foo.C));
Console.WriteLine(IsEnumFlagPresent(Foo.B | Foo.C, Foo.D));
}
}
答案 2 :(得分:11)
为了它的价值,我最近读到这个功能将成为.NET 4.0的一部分。具体来说,它是在Enum.HasFlag()
函数中实现的。
答案 3 :(得分:6)
我以前用过这个:
public static bool In<T>(this T me, T values)
where T : struct, IConvertible
{
return (me.ToInt64(null) & values.ToInt64(null)) > 0;
}
我喜欢它是你可以用这个干净的语法来调用它,因为在3.5中编译器可以推断出通用参数。
AttributeTargets a = AttributeTargets.Class;
if (a.In(AttributeTargets.Class | AttributeTargets.Module))
{
// ...
}
答案 4 :(得分:2)
您可以在没有泛型的情况下执行此操作:
static bool ContainsFlags(Enum value, Enum flag)
{
if (Enum.GetUnderlyingType(value.GetType()) == typeof(ulong))
return (Convert.ToUInt64(value) & Convert.ToUInt64(flag)) == Convert.ToUInt64(flag);
else
return (Convert.ToInt64(value) & Convert.ToInt64(flag)) == Convert.ToInt64(flag);
}
我在这种情况下转换为Int64,它应该处理除ulong之外的所有情况,这就是额外检查的原因......
答案 5 :(得分:2)
为什么不为此编写扩展方法? I did this in another post
public static class EnumerationExtensions {
public static bool Has<T>(this System.Enum type, T value) {
try {
return (((int)(object)type & (int)(object)value) == (int)(object)value);
}
catch {
return false;
}
}
//... etc...
}
//Then use it like this
bool hasValue = permissions.Has(PermissionTypes.Delete);
它可以使用一点改进(因为它假设所有内容都可以作为int转换),但它可以让你开始......
答案 6 :(得分:1)
值得指出的是,只要您知道自己正在使用特定的枚举,只需为所有整数类型提供一些静态重载即可。如果消费代码同样在where t : struct
如果你需要处理任意(struct)T
您目前无法在不使用C ++ / CLI的情况下将通用类型结构快速转换为某种备用按位形式(即粗略地说是reinterpret_cast)
generic <typename T>
where T : value class
public ref struct Reinterpret
{
private:
const static int size = sizeof(T);
public:
static int AsInt(T t)
{
return *((Int32*) (void*) (&t));
}
}
这将让你写:
static void IsSet<T>(T value, T flags) where T : struct
{
if (!typeof(T).IsEnum)
throw new InvalidOperationException(typeof(T).Name +" is not an enum!");
Type t = Enum.GetUnderlyingType(typeof(T));
if (t == typeof(int))
{
return (Reinterpret.AsInt(value) & Reinterpret.AsInt(flags)) != 0
}
else if (t == typeof(byte))
{
return (Reinterpret.AsByte(value) & Reinterpret.AsByte(flags)) != 0
}
// you get the idea...
}
您无法限制枚举。但是如果它们与非枚举类型一起使用,则这些方法的数学有效性不会改变,因此如果您可以确定它们可以转换为相关大小的结构,则可以允许它们。
答案 7 :(得分:0)
嗯,我不相信有办法做到这一点,因为没有适用于按位运算符的约束。
然而......你可以将你的枚举转换为int并执行它。
public static Boolean IsEnumFlagPresent(int value,int lookingForFlag)
{
return ((value & lookingForFlag) == lookingForFlag);
}
这有效,但可能会让某人感到困惑。
答案 8 :(得分:0)
问题很久了,但无论如何这里都有参考:
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;
}
答案 9 :(得分:0)
是基准测试4种不同方法的代码。结果显示在注释“ BENCHMARK:.. nSec”中的代码中。
“(((enum&flag)!= 0)'比HasFlag()函数快10倍。如果您处于紧密循环中,那么我认为最好接受它。
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;
}
答案 10 :(得分:0)
今天,您可以将c#语言版本设置为> = 7.3 并使用下一个代码作为参考:
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));
}
}