C#标志枚举按值或名称切换

C#标志枚举按值或名称切换,c#,enums,bit-manipulation,enum-flags,C#,Enums,Bit Manipulation,Enum Flags,我有一个标志enum,希望通过它的(long)值来切换一些值 我通过EF使用long字段将实际权限存储在数据库中,例如: public Permissions UsersPermissions { get; set; } 从客户端,我通过enum逐个获取值以切换正确的值,因此如果数据库字段包含 `Value1 | Value2 | Value3` 我得到一个4,我必须从用户权限中删除值3 如何通过其长版本获得正确的enum值 如何在UserPermissions字段中通过其长表示形式

我有一个标志
enum
,希望通过它的(
long
)值来切换一些值

我通过
EF
使用
long
字段将实际权限存储在数据库中,例如:

   public Permissions UsersPermissions { get; set; }
从客户端,我通过
enum
逐个获取值以切换正确的值,因此如果数据库字段包含

`Value1 | Value2 | Value3`
我得到一个4,我必须从用户权限中删除值3

  • 如何通过其长版本获得正确的
    enum
  • 如何在UserPermissions字段中通过其长表示形式切换一个值

我尝试了
usersPermissions |=permissionValue
,但它说我不能在
long
权限类型上使用
=
运算符。

必须在枚举上使用异或运算符。因此,如果您的权限值具有:

  • 价值1
  • 价值2
  • 价值3
  • 价值4
如果要删除值4,则必须执行以下操作:

var perm = Permissions.Value1 | Permissions.Value2 | Permissions.Value3 | Permissions.Value4;
perm = perm ^ Permissions.Value4;

必须对枚举执行异或运算符。因此,如果您的权限值具有:

  • 价值1
  • 价值2
  • 价值3
  • 价值4
如果要删除值4,则必须执行以下操作:

var perm = Permissions.Value1 | Permissions.Value2 | Permissions.Value3 | Permissions.Value4;
perm = perm ^ Permissions.Value4;

您必须在适当的位置对
long
Permissions
进行强制转换,如下所示:

Permissions perms = Permissions.Value1 | Permissions.Value2 | Permissions.Value3;
Console.WriteLine(perms); // Value1, Value2, Value3

long toRemove = 4;
// OR: long toRemove = (long) Permissions.Value3;

perms = (Permissions) ((long)perms & ~toRemove); // Use "& ~X" to remove bits set in X.

Console.WriteLine(perms); // Value1, Value2
这里重要的一点是,
~toRemove
返回
toRemove
的按位补码,从而为您提供一组位标志,您可以使用原始值
&
关闭在
toRemove
中设置的所有位

您必须将
perms
转换为
long
,才能执行此
&
操作


最后,通过
&
获得所需的结果后,您有一个
long
,您必须将其转换回
权限
,以获得正确的枚举类型作为最终答案。

您必须在适当的点对
long
权限
进行转换,如下所示:

Permissions perms = Permissions.Value1 | Permissions.Value2 | Permissions.Value3;
Console.WriteLine(perms); // Value1, Value2, Value3

long toRemove = 4;
// OR: long toRemove = (long) Permissions.Value3;

perms = (Permissions) ((long)perms & ~toRemove); // Use "& ~X" to remove bits set in X.

Console.WriteLine(perms); // Value1, Value2
这里重要的一点是,
~toRemove
返回
toRemove
的按位补码,从而为您提供一组位标志,您可以使用原始值
&
关闭在
toRemove
中设置的所有位

您必须将
perms
转换为
long
,才能执行此
&
操作


最后,通过
&
获得所需的结果后,您有一个
,您必须返回到
权限
,以获得正确的枚举类型作为最终答案。

据我所知,您的输入是一个数字,您希望它是一个
权限
。好吧,你可以从字面上投射它,即使它不是一个离散值。如果它是其中一个标志值的组合,那么这甚至可以“仅仅计算出”。C#枚举以这种方式进行强制转换非常聪明

下面是一个代码示例,可以实现您想要的功能

[Flags]
public enum TestEnum : long
{
    ValueNone = 0,  // You can't really "have" a Value0, it's an absence of values
    Value1 = 0x1,
    Value2 = 0x2,
    Value3 = 0x4,
    Value4 = 0x8
}

foreach(var enumVal in Enum.GetValues(typeof(TestEnum)))
{
    Console.WriteLine("val is: {0} long is: {1}", enumVal, (long)enumVal);
}

{
    Console.WriteLine("Start with 1 and 3, remove 3 from number");
    var testEnum = TestEnum.Value1 | TestEnum.Value3;
    Console.WriteLine("testEnum is: {0}({1})", testEnum, (long)testEnum);
    long testVal = 4;   // TestEnum.Value3
    var removeEnum = (TestEnum)testVal;
    removeEnum = ~removeEnum;
    testEnum &= removeEnum;
    Console.WriteLine("testEnum is: {0}({1})", testEnum, (long)testEnum);
}
{
    Console.WriteLine("Start with 1, 2, 4 and remove 1 and 4 from number");
    var testEnum = TestEnum.Value1 | TestEnum.Value2 | TestEnum.Value4;
    Console.WriteLine("testEnum is: {0}({1})", testEnum, (long)testEnum);
    long testVal = (long)TestEnum.Value1 | (long)TestEnum.Value4;   // Could also have added them
    var removeEnum = (TestEnum)testVal;
    Console.WriteLine("Removing: {0}({1})", removeEnum, (long)removeEnum);
    testEnum &= ~removeEnum;
    Console.WriteLine("testEnum is: {0}({1})", testEnum, (long)testEnum);
}
下面是一种通过最后一个元素的值获取枚举限制的方法:

{
    // Check the value to see what the range of the enumeration is
    var lastVal = Enum.GetValues(typeof(TestEnum)).Cast<TestEnum>().Last();
    long limit = (long)lastVal * 2;
    Console.WriteLine("Limit of flags for TestEnum is: " + limit);
    Func<long, bool> testLambda = x => x < limit;
    Console.WriteLine("Value of {0} within limit: {1}", 14, testLambda(14));
    Console.WriteLine("Value of {0} within limit: {1}", 16, testLambda(16));
    Console.WriteLine("Value of {0} within limit: {1}", 200, testLambda(200));
    Console.WriteLine("Value of {0} within limit: {1}", 0, testLambda(0));
    Console.WriteLine("Out of range looks like: " + (TestEnum)17);
    Console.WriteLine("In range looks like: " + (TestEnum)14);
}

我完全承认上面可能有更好的方法,但从根本上说,如果您有一个
[Flags]
enum,因此其中的所有内容都在一定程度上是“有效的”(所有组合都很好),只需检查您的值是否超出范围,然后将其从整数类型直接转换为enum类型,并将其终止。一旦它是您的标志类型,您就可以使用位运算符了。没问题,所以请先这样做。

从我所知道的情况来看,您的输入是一个数字,您希望它是一个
权限。好吧,你可以从字面上投射它,即使它不是一个离散值。如果它是其中一个标志值的组合,那么这甚至可以“仅仅计算出”。C#枚举以这种方式进行强制转换非常聪明

下面是一个代码示例,可以实现您想要的功能

[Flags]
public enum TestEnum : long
{
    ValueNone = 0,  // You can't really "have" a Value0, it's an absence of values
    Value1 = 0x1,
    Value2 = 0x2,
    Value3 = 0x4,
    Value4 = 0x8
}

foreach(var enumVal in Enum.GetValues(typeof(TestEnum)))
{
    Console.WriteLine("val is: {0} long is: {1}", enumVal, (long)enumVal);
}

{
    Console.WriteLine("Start with 1 and 3, remove 3 from number");
    var testEnum = TestEnum.Value1 | TestEnum.Value3;
    Console.WriteLine("testEnum is: {0}({1})", testEnum, (long)testEnum);
    long testVal = 4;   // TestEnum.Value3
    var removeEnum = (TestEnum)testVal;
    removeEnum = ~removeEnum;
    testEnum &= removeEnum;
    Console.WriteLine("testEnum is: {0}({1})", testEnum, (long)testEnum);
}
{
    Console.WriteLine("Start with 1, 2, 4 and remove 1 and 4 from number");
    var testEnum = TestEnum.Value1 | TestEnum.Value2 | TestEnum.Value4;
    Console.WriteLine("testEnum is: {0}({1})", testEnum, (long)testEnum);
    long testVal = (long)TestEnum.Value1 | (long)TestEnum.Value4;   // Could also have added them
    var removeEnum = (TestEnum)testVal;
    Console.WriteLine("Removing: {0}({1})", removeEnum, (long)removeEnum);
    testEnum &= ~removeEnum;
    Console.WriteLine("testEnum is: {0}({1})", testEnum, (long)testEnum);
}
下面是一种通过最后一个元素的值获取枚举限制的方法:

{
    // Check the value to see what the range of the enumeration is
    var lastVal = Enum.GetValues(typeof(TestEnum)).Cast<TestEnum>().Last();
    long limit = (long)lastVal * 2;
    Console.WriteLine("Limit of flags for TestEnum is: " + limit);
    Func<long, bool> testLambda = x => x < limit;
    Console.WriteLine("Value of {0} within limit: {1}", 14, testLambda(14));
    Console.WriteLine("Value of {0} within limit: {1}", 16, testLambda(16));
    Console.WriteLine("Value of {0} within limit: {1}", 200, testLambda(200));
    Console.WriteLine("Value of {0} within limit: {1}", 0, testLambda(0));
    Console.WriteLine("Out of range looks like: " + (TestEnum)17);
    Console.WriteLine("In range looks like: " + (TestEnum)14);
}

我完全承认上面可能有更好的方法,但从根本上说,如果您有一个
[Flags]
enum,因此其中的所有内容都在一定程度上是“有效的”(所有组合都很好),只需检查您的值是否超出范围,然后将其从整数类型直接转换为enum类型,并将其终止。一旦它是您的标志类型,您就可以使用按位运算符了。没问题,所以请先这样做。

我的问题是,我得到的是一个长值,而不是权限。值4。这就是为什么按位运算符不能以这种方式工作。如何才能说枚举的类型是long,而这正是在中心下使用的类型,因此您需要执行一些强制转换-perm=(perm=(Permissions)((long)perm^(long)4)我的问题是,我得到的是一个长值,而不是权限。Value4。这就是为什么按位运算符不能以这种方式工作。在您的例子中,枚举的类型是long,这是在中心下使用的类型,因此您需要执行一些强制转换-perm=(权限)((long)perm^(long)4)这是否回答了您的问题?我想,你应该使用
&
~
,就像附件中指出的那样。这是否回答了你的问题?我想,你应该使用
&
~
,就像附件中指出的那样