0

this is my setup:

public class MyEnums
{
    [Flags]
    public enum MyGroups
    {
        None = 0,
        Test1 = 1,
        Test2 = 2
    }
}


[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public sealed class MyAttribute : AuthorizeAttribute
{
    private readonly MyGroups _allowedGroups;

    public MyAttribute(MyGroups allowedGroups)
    {
        _allowedGroups = allowedGroups;
    }

    ...
}


[MyAttribute(MyGroups.Test1 | MyGroups.Test2)]
public class MyController : Controller
{
    ...
}

I specifically do not understand what is happening in the [MyAttribute(MyGroups.Test1 | MyGroups.Test2)] part on the controller side. Am I instantiating multiple attributes (?)"

[MyAttribute(MyGroups.Test1)]
[MyAttribute(MyGroups.Test2)]

Thanks in advance!

Tarta
  • 1,729
  • 1
  • 29
  • 63
  • 1
    This is what's called a flag enum and it's "used whenever the enum represents a collection of possible values rather an a single value" from [this](https://stackoverflow.com/q/8447/9363973) excellent Q&A. It basically allows you signal to a user that the values in the enum can appear in any grouping. The `AttributeUsage` is an excellent example. In your code it specifies that `MyAttribute` is valid on Classes and Methods – MindSwipe Jul 16 '20 at 08:50
  • There’s only one attribute so there’s no instantiating multiple attributes – Sami Kuhmonen Jul 16 '20 at 08:52
  • 1
    As MindSwipe has mentioned, you have only one attribute, but its value can be a mix of `MyGroups` enum. in your `[MyAttribute(MyGroups.Test1 | MyGroups.Test2)]` the value of `allowedGroups` would be 3 (both `MyGroups.Test1` and `MyGroups.Test2`) – Cleptus Jul 16 '20 at 08:56
  • Totally clear, thanks everyone! I thought it had to do with the attribute in my controller itself while instead it had to do with [Flag] attribute. Thanks again!:) – Tarta Jul 16 '20 at 09:00

1 Answers1

1

| is the bitwise OR operator.

You are not defining 2 attributes, you are defining 1, and passing an enum that has the value Test1 or Test2.

It might be clearer if you define your enum using binary literals:

[Flags]
public enum MyGroups
{
    None = 0b0000,  // 0000
    Test1 = 0b0001, // 0001
    Test2 = 0b0010  // 0010
}

When you do a bitwise OR, you check each binary digit, and the result is where 1 is present in either value (as opposed to bitwise AND, which requires both digits to be 1).

So MyGroups.Test1 | MyGroups.Test2 is equivalent to:

  0001
| 0010
= 0011

When using this technique, it is important to use square numbers for the enum values to ensure that the bitwise operations do not result in a value that clashes with a single enum value. So if you were to extend your enum you should do the following:

[Flags]
public enum MyGroups
{
    None = 0b0000,  // 0000
    Test1 = 0b0001, // 0001
    Test2 = 0b0010, // 0010
    Test3 = 0b0100, // 0100
    Test4 = 0b1000  // 1000
}

Or using integer literals:

[Flags]
public enum MyGroups
{
    None = 0,
    Test1 = 1,
    Test2 = 2,
    Test3 = 4,
    Test4 = 8
}
Johnathan Barclay
  • 18,599
  • 1
  • 22
  • 35