Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple enums or generic enum

Tags:

c#

enums

I created multiple enums for notifications in my app. Each enum is tied to a module. I did it this way because if I were to use a single enum, it would get way too big. So, module1NotificationTypes, module2NotificationTypes, etc.

I want to have a single notifications method that will receive the notification type. Is there a way to receive a single generic enum value that I can convert to the appropriate module enum -- as below?

public void sendNotification(GenericEnum notificationType)
{
   // Try to convert the generic enum to module1Notification or module2Notification
}

Or am I going to have to expect multiple enum values and set the unused ones to "Undefined" so that I can skip them?

public void sendNotification(module1NotificationTypes mod1, module2NotificationTypes mod2)
{
   if(mod1 != Module1Notifications.Undefined)
   {
      // We know we received module 1 notification request
   }
   else if(mod2 != Module2Notifications.Undefined)
   {
      // We know we received module 2 notification request
   }
}
like image 553
Sam Avatar asked Jun 10 '26 13:06

Sam


2 Answers

Why splitting enums? you are loosing the benefit of enums.

public void sendNotification(NotificationEnum notificationType)
{
   switch(notificationType)
   {
       case NotificationEnum.module_1:
             // We know we received module 1 notification request
       break;
       case NotificationEnum.module_2:
            // We know we received module 2 notification request
       break;
   }
}

If its possible to have multiple types at once you can mark your enum with [Flags].

You can even use dictionary to map each enum value to some function ,I update my answer soon.

You can define your enum like this. note that by default you are limited to maximum of 32 values. if you use ulong then you are limited to maximum of 64 values.

[Flags]
public enum NotificationEnum : ulong
{
    module_1 = 1<<0,
    module_2 = 1<<1,
    module_3 = 1<<2, 
    // and so on
}

use the following to enumerate through flagged enum and get all the flags.

public static class Enumerations
{
    public static IEnumerable<Enum> GetAllFlags(this Enum values)
    {
        foreach (Enum value in Enum.GetValues(values.GetType()))
        {
            if (values.HasFlag(value))
            {
                yield return value;
            }
        }
    }
}

Now create a dictionary of enum to action.

Dictionary<NotificationEnum, Action> Actions = new Dictionary<NotificationEnum, Action>()
{
    { NotificationEnum.module_1, () => 
         {
             // We know we received module 1 notification request
         }
    },
    { NotificationEnum.module_2, () => 
         {
             // We know we received module 2 notification request
         }
    },
    // and so on
};

your final method is simple.

public void sendNotification(NotificationEnum notificationType)
{
     foreach(var action in notificationType.GetAllFlags())
     {
         action();
     }
}
like image 181
M.kazem Akhgary Avatar answered Jun 12 '26 10:06

M.kazem Akhgary


There is nothing like a generic enum type, but you can use the fact that enums are on top of an integer type (if nothing is specified it is Int32). That makes them easily convertible to the underlying type. If they share a type, they are also easily convertible to each other.

Your sendNotification method would not make much sense if there wouldn't be a shared set of enum values. You can define them in an enum (probably with an explicit value to avoid collisions):

public enum NotificationShared {
    Undefined = 0
}

When you define your module enum, you can refer to that:

public enum module1Notification {
    Undefined = NotificationShared.Undefined
}

public enum module2Notification {
    Undefined = NotificationShared.Undefined
}

Again, there is no generic way to deal with these enums, but now you at least have common values and you are guaranteed that a conversion will yield semantically the same values. If you want to go for only one method, you can only avoid the boxing with an object parameter, when you use a generic method with a value type constraint:

public void sendNotification<T>(T notificationType) where T : struct
{
   // Convert to shared enum type
   NotificationShared notification = (NotificationShared)notificationType;
}

That is indeed a bit ugly, because you are not type-safe here and you will have no static type checking. On the other hand this solution would come with the advantage that you don't introduce a dependency on your derived enums and thus would reduce coupling and could be implemented in the same assembly as NotificationShared.

If you want to avoid the disadvantages of that solution, overloads are your best choice to avoid code duplication:

public void sendNotification(NotificationShared notificationType)
{
    // Use shared enum type
}

public void sendNotification(module1Notification notificationType)
{
    sendNotification((NotificationShared)notificationType);
}

public void sendNotification(module2Notification notificationType)
{
    sendNotification((NotificationShared)notificationType);
}

That might be all not optimal, but it is be the best way to handle the situation.

like image 32
Sefe Avatar answered Jun 12 '26 12:06

Sefe



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!