C# флажок перечисления по значению или имени - PullRequest
0 голосов
/ 24 февраля 2020

У меня есть флаг 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.

Ответы [ 3 ]

1 голос
/ 24 февраля 2020

Вы должны выполнить некоторое приведение к 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, который вы должны привести к Permissions, чтобы получить правильное перечисление введите в качестве окончательного ответа.

1 голос
/ 24 февраля 2020

Из того, что я могу сказать, вы вводите число, и вы хотите, чтобы оно было Permissions. Ну, вы можете буквально разыграть его, даже если это не одно из дискретных значений. Это даже «просто выяснит», если это комбинация одного из значений флага. 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] enum, и, следовательно, все внутри него является «допустимым» до некоторой степени (все комбинации в порядке), просто проверьте, находится ли ваше значение вне диапазона, а затем приведите его из целочисленного типа непосредственно к типу enum и назовите его день. Как только это ваш тип флага, вы можете без проблем использовать побитовые операторы, так что просто сделайте это в первую очередь.

0 голосов
/ 24 февраля 2020

Вы должны сделать исключительный оператор ИЛИ для перечисления. Поэтому, если у вас есть значение разрешения:

  • Значение1
  • Значение2
  • Значение3
  • Значение4,

и вы Чтобы удалить Value4, вам нужно будет сделать следующее:

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