C# 标志枚举按值或名称切换
C# flag enum toggle by value or name
我有一个 Flags enum
并且想通过它的 (long
) 值来切换一些值。
[Flags]
public enum Permissions : long
{
Value0 = 0,
Value1 = 0x1,
Value2 = 0x2,
Value3 = 0x4,
//etc
}
我通过 EF
使用 long
字段将实际权限存储在数据库中,例如:
public Permissions UsersPermissions { get; set; }
从客户端我一个一个地获取值以通过 enum
切换正确的值,所以如果数据库字段包含
`Value1 | Value2 | Value3`
我得到 4 我必须从用户权限中删除 Value3。
- 如何通过长版本获得正确的
enum
值?
- 如何通过其长表示切换 UserPermissions 字段中的一个值?
我试过 usersPermissions |= permissionValue
但它说我不能在 long
和 Permission
类型上使用 |=
运算符。
您必须对枚举执行异或运算符。因此,如果您的权限值具有:
- 值 1
- 值 2
- 值 3
- 值 4,
如果您想删除 Value4,您必须这样做:
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
returns toRemove
的按位补码,从而为您提供一组位标志,您可以 &
使用原始值为了关闭在 toRemove
.
中设置的所有位
您必须将 perms
转换为 long
才能执行此 &
操作。
最后,通过 &
获得了您需要的结果,您有一个 long
,您必须将其转换回 Permissions
以获得正确的枚举类型作为最终答案。
据我所知,您输入的是一个数字,您希望它是 Permissions
。好吧,你可以从字面上转换它,即使它不是离散值之一。如果它是其中一个标志值的组合,那甚至 "just figure out" 。 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);
}
输出:
val is: ValueNone long is: 0
val is: Value1 long is: 1
val is: Value2 long is: 2
val is: Value3 long is: 4
val is: Value4 long is: 8
Start with 1 and 3, remove 3 from number
testEnum is: Value1, Value3(5)
testEnum is: Value1(1)
Start with 1, 2, 4 and remove 1 and 4 from number
testEnum is: Value1, Value2, Value4(11)
Removing: Value1, Value4(9)
testEnum is: Value2(2)
Limit of flags for TestEnum is: 16
Value of 14 within limit: True
Value of 16 within limit: False
Value of 200 within limit: False
Value of 0 within limit: True
Out of range looks like: 17
In range looks like: Value2, Value3, Value4
我完全承认上面可能有更好的方法,但从根本上说,如果你有一个 [Flags]
枚举,那么它里面的所有东西在一定程度上都是 "valid"(所有组合很好),只需检查您的值是否超出范围,然后将其从整数类型直接转换为枚举类型并收工。一旦它是你的标志类型,你就可以毫无问题地使用按位运算符,所以先这样做吧。
我有一个 Flags enum
并且想通过它的 (long
) 值来切换一些值。
[Flags]
public enum Permissions : long
{
Value0 = 0,
Value1 = 0x1,
Value2 = 0x2,
Value3 = 0x4,
//etc
}
我通过 EF
使用 long
字段将实际权限存储在数据库中,例如:
public Permissions UsersPermissions { get; set; }
从客户端我一个一个地获取值以通过 enum
切换正确的值,所以如果数据库字段包含
`Value1 | Value2 | Value3`
我得到 4 我必须从用户权限中删除 Value3。
- 如何通过长版本获得正确的
enum
值? - 如何通过其长表示切换 UserPermissions 字段中的一个值?
我试过 usersPermissions |= permissionValue
但它说我不能在 long
和 Permission
类型上使用 |=
运算符。
您必须对枚举执行异或运算符。因此,如果您的权限值具有:
- 值 1
- 值 2
- 值 3
- 值 4,
如果您想删除 Value4,您必须这样做:
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
returns toRemove
的按位补码,从而为您提供一组位标志,您可以 &
使用原始值为了关闭在 toRemove
.
您必须将 perms
转换为 long
才能执行此 &
操作。
最后,通过 &
获得了您需要的结果,您有一个 long
,您必须将其转换回 Permissions
以获得正确的枚举类型作为最终答案。
据我所知,您输入的是一个数字,您希望它是 Permissions
。好吧,你可以从字面上转换它,即使它不是离散值之一。如果它是其中一个标志值的组合,那甚至 "just figure out" 。 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);
}
输出:
val is: ValueNone long is: 0
val is: Value1 long is: 1
val is: Value2 long is: 2
val is: Value3 long is: 4
val is: Value4 long is: 8
Start with 1 and 3, remove 3 from number
testEnum is: Value1, Value3(5)
testEnum is: Value1(1)
Start with 1, 2, 4 and remove 1 and 4 from number
testEnum is: Value1, Value2, Value4(11)
Removing: Value1, Value4(9)
testEnum is: Value2(2)
Limit of flags for TestEnum is: 16
Value of 14 within limit: True
Value of 16 within limit: False
Value of 200 within limit: False
Value of 0 within limit: True
Out of range looks like: 17
In range looks like: Value2, Value3, Value4
我完全承认上面可能有更好的方法,但从根本上说,如果你有一个 [Flags]
枚举,那么它里面的所有东西在一定程度上都是 "valid"(所有组合很好),只需检查您的值是否超出范围,然后将其从整数类型直接转换为枚举类型并收工。一旦它是你的标志类型,你就可以毫无问题地使用按位运算符,所以先这样做吧。