gpt4 book ai didi

c# - 反转枚举标志

转载 作者:行者123 更新时间:2023-11-30 14:29:46 27 4
gpt4 key购买 nike

假设我有以下标志:

[Flags]
public enum Foo
{
None = 0,
Foo1 = 1,
Foo2 = 2,
Foo4 = 4,
Foo8 = 8
}

现在我有一个变量 foo:

var foo = Foo.Foo1 | Foo.Foo4;

我要得到的是下面的foo的倒置标志。那将意味着这样的事情:

Foo.Foo2 | Foo.Foo8

我试过 ~ 运算符。但是由于我的枚举是一个 int32 值,它会反转所有 32 位。但实际上我只需要反转我的 Foo enum 使用的位。

编辑:Foo1 | Foo4 将等于以下位掩码:

00000000 00000000 00000000 00000101

如果您使用 ~ 运算符反转该位掩码,您将得到以下结果:

11111111 11111111 11111111 11111010

我想要的结果是:

00000000 00000000 00000000 00001010

如您所见。我只想反转 Foo 枚举使用的位。不是整个 32 整数值的所有位。

最佳答案

你想要做的是将枚举的所有值组合起来,然后用你当前值的补码来掩盖它。

        Foo value = Foo.Foo4;
Foo allValues = (Foo)0;
foreach (var v in Enum.GetValues(typeof(Foo)))
allValues |= (Foo)v;
var compliment = allValues & ~(value);

或者,您可以将这些值与 Linq 结合起来并静态缓存它们以提高性能:

    public static class FooHelper
{
private readonly static Foo allValues = ((Foo[])Enum.GetValues(typeof(Foo))).Aggregate((Foo)0, (all, cur) => all | cur);

public static Foo AllValues { get { return allValues ; } }
}

然后:

        var foo = Foo.Foo1 | Foo.Foo4;
var compliment = FooHelper.AllValues & ~(foo);

更新

如果你想要一个泛型方法来组合一个枚举的所有标志值,你可以这样做:

var compliment = EnumHelper.GetAll<Foo>() & ~(value);

关于枚举的基本数据缓存在惰性参数化单例实例中:

/// <summary>
/// Contains generic utilities for enums, constrained for enums only.
/// </summary>
public sealed class EnumHelper : Enums<Enum>
{
private EnumHelper()
{
}
}

/// <summary>
/// For use by EnumHelper, not for direct use.
/// </summary>
public abstract class Enums<TEnumBase> where TEnumBase : class, IConvertible
{
// Generic singleton remembering basic properties about specified enums, cached for performance.
sealed class DataSingleton<TEnum> where TEnum : struct, TEnumBase
{
static readonly DataSingleton<TEnum> instance = new DataSingleton<TEnum>();

readonly bool isSigned;
readonly TEnum allValues;
readonly bool hasFlags;

// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static DataSingleton()
{
}

DataSingleton()
{
isSigned = GetIsSigned();
allValues = GetAll();
hasFlags = GetHasFlags();
}

static bool GetHasFlags()
{
var attributes = typeof(TEnum).GetCustomAttributes(typeof(FlagsAttribute), false);
return attributes != null && attributes.Length > 0;
}

static bool GetIsSigned()
{
var underlyingType = Enum.GetUnderlyingType(typeof(TEnum));
bool isSigned = (underlyingType == typeof(long) || underlyingType == typeof(int) || underlyingType == typeof(short) || underlyingType == typeof(sbyte));
bool isUnsigned = (underlyingType == typeof(ulong) || underlyingType == typeof(uint) || underlyingType == typeof(ushort) || underlyingType == typeof(byte));
if (!isSigned && !isUnsigned)
throw new InvalidOperationException();
return isSigned;
}

static TEnum GetAll()
{
if (GetIsSigned())
{
long value = 0;
foreach (var v in Enum.GetValues(typeof(TEnum)))
// Not sure I need the culture but Microsoft passes it in Enum.ToUInt64(Object value) - http://referencesource.microsoft.com/#mscorlib/system/enum.cs
value |= Convert.ToInt64(v, CultureInfo.InvariantCulture);
return (TEnum)Enum.ToObject(typeof(TEnum), value);
}
else
{
ulong value = 0;
foreach (var v in Enum.GetValues(typeof(TEnum)))
// Not sure I need the culture but Microsoft passes it in Enum.ToUInt64(Object value) - http://referencesource.microsoft.com/#mscorlib/system/enum.cs
value |= Convert.ToUInt64(v, CultureInfo.InvariantCulture);
return (TEnum)Enum.ToObject(typeof(TEnum), value);
}
}

public bool HasFlags { get { return hasFlags; } }

public bool IsSigned { get { return isSigned; } }

public TEnum AllValues { get { return allValues; } }

public static DataSingleton<TEnum> Instance { get { return instance; } }
}

private static void ThrowOnEnumWithoutFlags<TEnum>(DataSingleton<TEnum> data) where TEnum : struct, TEnumBase
{
if (!data.HasFlags)
{
throw (new ArgumentException("The generic argument [<TEnum>] must be an enumeration with the [FlagsAttribute] applied.", "TEnum: " + typeof(TEnum).FullName));
}
}

public static TEnum GetAll<TEnum>() where TEnum : struct, TEnumBase
{
var data = DataSingleton<TEnum>.Instance;
ThrowOnEnumWithoutFlags<TEnum>(data);
return data.AllValues;
}
}

关于c# - 反转枚举标志,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25217158/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com