枚举.HasFlag与位检查和操作符检查
本文关键字:操作符 检查 检查和 HasFlag 枚举 | 更新日期: 2023-09-27 18:06:55
如果您有一个用于位标志的enum
,即
[Flags]
internal enum _flagsEnum : byte
{
None = 0, //00000000
Option1 = 1, //00000001
Option2 = 1 << 1, //00000010
Option3 = 1 << 2, //00000100
Option4 = 1 << 3, //00001000
Option5 = 1 << 4, //00010000
Option6 = 1 << 5, //00100000
Option7 = 1 << 6, //01000000
Option8 = 1 << 7, //10000000
All = Byte.MaxValue,//11111111
}
_flagsEnum myFlagsEnum = _flagsEnum.None;
做…比较快吗
bool hasFlag = myFlagsEnum.HasFlag(_flagsEnum.Option1);
or to do.
bool hasFlag = myFlagsEnum & _flagsEnum.Option1 != 0
如果检查多个标志之间存在性能差异,那么也要考虑到这一点。
通常我会检查引用源,但在这种情况下是Enum。HasFlags只是去外部InternalHasFlags,所以我不知道它在做什么
使用HasFlag
是有性能代价的,因为实现验证你传递的enum
值与标志的类型相同。
解决了这个差异后,实现进行了高度优化,以避免将较短的类型(如byte
)提升为int
:
switch (pMTThis->GetNumInstanceFieldBytes()) {
case 1:
cmp = ((*(UINT8*)pThis & *(UINT8*)pFlags) == *(UINT8*)pFlags);
break;
case 2:
cmp = ((*(UINT16*)pThis & *(UINT16*)pFlags) == *(UINT16*)pFlags);
break;
case 4:
cmp = ((*(UINT32*)pThis & *(UINT32*)pFlags) == *(UINT32*)pFlags);
break;
case 8:
cmp = ((*(UINT64*)pThis & *(UINT64*)pFlags) == *(UINT64*)pFlags);
break;
default:
// should not reach here.
UNREACHABLE_MSG("Incorrect Enum Type size!");
break;
}
ReflectionEnum::InternalHasFlag
的源代码可以在这里找到。
尽管成本相对较高,但除了最极端的情况外,这可能无关紧要。我建议保留它,除非您的分析器指出该调用是程序中最大的瓶颈。
不安全
这个怎么样?在我的基准测试中,比HasFlag快25%,比位慢10%-15%,但是通用。
也许有人能优化它
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static unsafe Boolean HasFlags<T>(T* first, T* second) where T : unmanaged, Enum
{
Byte* pf = (Byte*) first;
Byte* ps = (Byte*) second;
for (Int32 i = 0; i < sizeof(T); i++)
{
if ((pf[i] & ps[i]) != ps[i])
{
return false;
}
}
return true;
}
/// <remarks>Faster analog of Enum.HasFlag</remarks>
/// <inheritdoc cref="Enum.HasFlag"/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe Boolean HasFlags<T>(this T first, T second) where T : unmanaged, Enum
{
return HasFlags(&first, &second);
}