多个枚举或通用枚举

3
我在我的应用程序中创建了多个通知枚举。每个枚举都与一个模块相关联。我这样做是因为如果我使用单个枚举,它会变得过于庞大。所以,module1NotificationTypes、module2NotificationTypes等。
我想要一个单一的通知方法,它将接收通知类型。是否有一种方式可以接收单个通用枚举值,我可以将其转换为适当的模块枚举 - 如下所示?
public void sendNotification(GenericEnum notificationType)
{
   // Try to convert the generic enum to module1Notification or module2Notification
}

或者我需要期望多个枚举值存在,并将未使用的设置为"Undefined",以便我可以跳过它们吗?

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
   }
}

1
这就是重载的作用。每个枚举类型只需要有一个方法。从外部看起来就像是一个单一的方法。 - Blorgbeard
4个回答

1

我认为没有办法像你想的那样枚举枚举。MSDN上的这篇文章可能是处理您情况的最紧凑的方式。请访问以下链接获取更多信息。

编辑 1:

链接中给出的示例有两个枚举类型(Alpha和Beta)和一个获取枚举值的方法。我在下面包含了该代码的片段:

枚举:

public enum Alpha { One, Two, Three }
public enum Beta { Four, Five, Six }

存取方法:
public T GetOne<T>(object o){
    T one = (T)Enum.Parse(typeof(T), o.ToString());
    return one;
}

使用该方法:
MessageBox.Show(GetOne<Alpha>(Alpha.One).ToString());

1
你能否提供一些关于这篇文章所解释的内容的描述?仅仅将用户重定向到文章是不好的做法,因为文章可能会被删除! - kat1330

1
为什么要拆分枚举?这样你就失去了枚举的好处。
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;
   }
}

如果可能同时拥有多个类型,则可以在枚举上标记[Flags]。
甚至可以使用字典将每个枚举值映射到某个函数,我很快会更新我的答案。
您可以像这样定义您的枚举。请注意,默认情况下,您最多只能拥有32个值。如果使用ulong,则最多只能拥有64个值。
[Flags]
public enum NotificationEnum : ulong
{
    module_1 = 1<<0,
    module_2 = 1<<1,
    module_3 = 1<<2, 
    // and so on
}

使用以下方法枚举标记枚举并获取所有标记。
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;
            }
        }
    }
}

现在创建一个枚举到操作的字典。
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
};

你的最终方法很简单。
public void sendNotification(NotificationEnum notificationType)
{
     foreach(var action in notificationType.GetAllFlags())
     {
         action();
     }
}

正如我在原帖中提到的那样,一个枚举会变得过于庞大。条目太多了,难以管理。你的解决方案现在并不起作用。我考虑过类似这样的解决方案,但是在这种情况下,实际的枚举值并没有被接收到。例如,module1NotificationTypes.DoSomething。你只发送了枚举类型而不是通知类型。 - Sam
@Sam 看一下更新。此外,你可以使用 Action<T>Func<T> 或其他类型的委托,而不是 Action。它非常灵活。你仍然可以为不同的模块使用不同的字典,并拥有多个枚举。 - M.kazem Akhgary
1
这真的是一个很好的解决方案,因为它减少了Cyclomatic Complexity - Erik Philips
1
@ErikPhilips: 这可能会减少圈复杂度,但它引入了所有其他复杂性呢?这不是一个明显的结构,因此比更直接的解决方案更难以理解。 - Sefe
@Sefe,您的观点很有道理,但如果没有具体细节,我就无法评论。我不知道为什么一个枚举比多个枚举更复杂。这里的任何答案都不是基于要求的直截了当的答案。如果这是我的问题,我肯定会根据这个问题的难度编写单元测试,并尽可能少地编写测试代码(这就涉及到圈复杂度)。 - Erik Philips

1
没有通用的枚举类型,但是你可以利用枚举类型基于整数类型(如果没有指定,则为Int32)的事实。这使得它们很容易转换为底层类型。如果它们共享一个类型,它们也很容易相互转换。
如果没有共享的枚举值,您的sendNotification方法将没有多大意义。您可以在枚举中定义它们(可能使用显式值以避免冲突):
public enum NotificationShared {
    Undefined = 0
}

当您定义模块枚举时,可以引用它:
public enum module1Notification {
    Undefined = NotificationShared.Undefined
}

public enum module2Notification {
    Undefined = NotificationShared.Undefined
}

再次强调,没有通用的方法来处理这些枚举,但现在您至少具有共同的值,并且可以保证转换将产生语义上相同的值。如果您只想使用一种方法,则只能使用带有值类型约束的通用方法来避免装箱,使用object参数:

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

这确实有点丑陋,因为你在这里没有类型安全,并且没有静态类型检查。另一方面,这种解决方案的优点是,你不会引入对派生枚举的依赖,从而减少耦合并可以在与“NotificationShared”相同的程序集中实现。
如果你想避免这种解决方案的缺点,重载是避免代码重复的最佳选择:
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);
}

这可能不是最优解,但它是处理情况的最佳方式。


0

你可以使用方法的重载技术

public void sendNotification(module1NotificationTypes mod)
{
   //handle notification type
}

public void sendNotification(module2NotificationTypes mod)
{

}

此外,您可以进行一些不太正规的操作,分割枚举值的范围

enum module1NotificationTypes
{
   Type1Test1 = 1,
   Type1Test2 = 2,
   ...
}

enum module2NotificationTypes
{
   Type2Test1 = 101,
   Type2Test2 = 102,
}

接下来创建一个方法,该方法接受int或其他你的枚举类型使用的整数类型(因为所有枚举在编译时都是数字)。但这可能比仅重载方法更慢。另一方面,编译器可以优化这种行为并且不进行转换。

public void sendNotification(int typeNum){
   if (typeNum <= 100)
   {  
      if (!Emum.IsDefined(typeof(module1NotificationTypes), typeNum))
      { 
         throw new ArgumentException();
      }
      //DO Processing
   }
   else 
   {
      if (!Emum.IsDefined(typeof(module2NotificationTypes), typeNum))
      { 
         throw new ArgumentException();
      }
      //DO Processing
   }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接