【问题标题】:How to add extension methods to Enums如何向 Enums 添加扩展方法
【发布时间】:2013-03-01 13:12:55
【问题描述】:

我有这个枚举代码:

enum Duration { Day, Week, Month };

我可以为这个 Enum 添加扩展方法吗?

【问题讨论】:

  • 简短回答,是的。在这种特定情况下,您可能需要考虑使用TimeSpan
  • 在枚举上使用扩展方法会让我觉得很脏。创建一个类来封装所需的内容。保持枚举尽可能简单。如果您需要更多与之关联的逻辑,则创建一个 Duration 类,该类公开日、周、月以及包含扩展方法中的任何其他逻辑。
  • 我喜欢为标志组提供枚举扩展方法。我更喜欢 if 子句,例如 Day.IsWorkday() 而不是 (Day & Days.Workday) > 0Days.Workday 定义为 Monday | Tuesday ... | Friday。在我看来,前者更清楚,而后者也完全实现了。

标签: c# .net enums


【解决方案1】:

当然你可以,例如,你想在你的enum 值上使用DescriptionAttribue

using System.ComponentModel;

public enum Duration 
{ 
    [Description("Eight hours")]
    Day,

    [Description("Five days")]
    Week,

    [Description("Twenty-one days")] 
    Month 
}

现在您希望能够执行以下操作:

Duration duration = Duration.Week;
var description = duration.GetDescription(); // will return "Five days"

你的扩展方法GetDescription()可以这样写:

using System.ComponentModel;
using System.Reflection;

public static string GetDescription(this Enum value)
{
    FieldInfo fieldInfo = value.GetType().GetField(value.ToString());
    if (fieldInfo == null) return null;
    var attribute = (DescriptionAttribute)fieldInfo.GetCustomAttribute(typeof(DescriptionAttribute));
    return attribute.Description;
}

【讨论】:

  • 我希望创建一个扩展,几乎与您的示例完全一样,除了我使用 DisplayAttribute Localized GetDescription。欢呼
  • 这是一个不错的选择,虽然我认为命名空间只是 System.ComponentModel?
  • 很好的视角,感谢您展示实现以及扩展代码。继续:通过你的实现,你也可以这样调用它: var description = Duration.Week.GetDescription();
【解决方案2】:

一个简单的解决方法。

public static class EnumExtensions
{
    public static int ToInt(this Enum payLoad) {

        return ( int ) ( IConvertible ) payLoad;

    }
}

int num = YourEnum.AItem.ToInt();
Console.WriteLine("num : ", num);

【讨论】:

    【解决方案3】:

    我们刚刚为 c# https://github.com/simonmau/enum_ext做了一个枚举扩展

    这只是 typesafeenum 的一个实现,但它工作得很好,所以我们制作了一个包来分享 - 玩得开心

    public sealed class Weekday : TypeSafeNameEnum<Weekday, int>
    {
        public static readonly Weekday Monday = new Weekday(1, "--Monday--");
        public static readonly Weekday Tuesday = new Weekday(2, "--Tuesday--");
        public static readonly Weekday Wednesday = new Weekday(3, "--Wednesday--");
        ....
    
        private Weekday(int id, string name) : base(id, name)
        {
        }
    
        public string AppendName(string input)
        {
            return $"{Name} {input}";
        }
    }
    

    我知道这个例子有点没用,但你明白了 ;)

    【讨论】:

      【解决方案4】:

      所有答案都很好,但他们正在谈论将扩展方法添加到特定类型的枚举。

      如果您想为所有枚举添加一个方法,例如返回一个当前值的 int 而不是显式转换,该怎么办?

      public static class EnumExtensions
      {
          public static int ToInt<T>(this T soure) where T : IConvertible//enum
          {
              if (!typeof(T).IsEnum)
                  throw new ArgumentException("T must be an enumerated type");
      
              return (int) (IConvertible) soure;
          }
      
          //ShawnFeatherly funtion (above answer) but as extention method
          public static int Count<T>(this T soure) where T : IConvertible//enum
          {
              if (!typeof(T).IsEnum)
                  throw new ArgumentException("T must be an enumerated type");
      
              return Enum.GetNames(typeof(T)).Length;
          }
      }
      

      IConvertible 背后的技巧是它的继承层次结构,请参阅MDSN

      感谢ShawnFeatherly for his answer

      【讨论】:

      • 最佳答案!
      • 同上。如果我直接调用扩展名(例如MyExtention.DoThing(myvalue))但实际上并没有附加到枚举(例如myvalue.DoThing()
      • 仅供参考,C# 7.3 现在支持 Enum 作为泛型类型约束
      【解决方案5】:

      据此site

      扩展方法提供了一种为现有类编写方法的方法,您的团队中的其他人可能会实际发现和使用这种方法。鉴于枚举和其他任何类一样,您可以扩展它们应该不会太令人惊讶,例如:

      enum Duration { Day, Week, Month };
      
      static class DurationExtensions 
      {
        public static DateTime From(this Duration duration, DateTime dateTime) 
        {
          switch (duration) 
          {
            case Day:   return dateTime.AddDays(1);
            case Week:  return dateTime.AddDays(7);
            case Month: return dateTime.AddMonths(1);
            default:    throw new ArgumentOutOfRangeException("duration");
          }
        }
      }
      

      我认为枚举通常不是最好的选择,但至少这可以让你集中一些 switch/if 处理并将它们抽象一点,直到你可以做得更好。记得检查值是否也在范围内。

      您可以在 Microsft MSDN 上阅读更多 here

      【讨论】:

      • 我相信“枚举是邪恶的”评论是不合适的,但有现实的基础。我确实发现枚举可能是一个过度使用的问题,因为它们会将您锁定在某些上下文和行为中。
      • C# 中的枚举有点糟糕,因为它可以编译并运行:Duration d = 0;
      • Given that enums are classes 不,它们不是类。
      • 我只在直接涉及枚举时才使用这种扩展,例如一周中的几天和扩展方法 IsWeekday()、IsWeekendday()。但是类是用来封装行为的,所以如果要封装很多或复杂的行为,类可能会更好。如果它是有限的和基本的,我个人认为枚举的扩展是可以的。与大多数设计决策一样,选择之间存在模糊界限 (IMO)。值得注意的是,扩展只能在顶级静态类上完成,而不是嵌套类。如果你的枚举是一个类的一部分,你需要创建一个类。
      • @WingerSendon 如果您在 VS2019 中对 Enum(不是 enum)按 F12,它会将您带到包含 public abstract class Enum : ValueType, IComparable, ... 的元数据 - 所以它对我来说就像一门课,因为我认为枚举和 Enum 是同义词。
      【解决方案6】:

      MSDN

      public static class Extensions
      {
        public static string SomeMethod(this Duration enumValue)
        {
          //Do something here
          return enumValue.ToString("D"); 
        }
      }
      

      【讨论】:

      • 枚举上的 void 返回值有点奇怪。我会考虑一个更真实的样本。
      • @psubsee2003 OP 肯定有足够的知识来改变它以满足他的需要?为什么样本很重要,回答最初的问题就足够了。
      • 我是唯一一个发现 MSDN 上的代码示例很奇怪的人吗?大多数时候,您需要付出一些真正的努力才能了解他们想要做什么!
      【解决方案7】:

      您还可以向 Enum 类型添加扩展方法,而不是 Enum 的实例:

      /// <summary> Enum Extension Methods </summary>
      /// <typeparam name="T"> type of Enum </typeparam>
      public class Enum<T> where T : struct, IConvertible
      {
          public static int Count
          {
              get
              {
                  if (!typeof(T).IsEnum)
                      throw new ArgumentException("T must be an enumerated type");
      
                  return Enum.GetNames(typeof(T)).Length;
              }
          }
      }
      

      您可以通过以下方式调用上述扩展方法:

      var result = Enum<Duration>.Count;
      

      这不是真正的扩展方法。它之所以有效,是因为 Enum 是与 System.Enum 不同的类型。

      【讨论】:

      • 该类可以是static 以确保其所有方法的行为都像扩展吗?
      • 对于未来的读者:Enum&lt;T&gt; 的名称歧义有点令人困惑。该类也可以称为EnumUtils&lt;T&gt;,方法调用将解析为EnumUtils&lt;Duration&gt;.Count
      • 从 C# 7.3 开始,您实际上可以使用 where T : struct, IConvertible 而不是 where T : System.Enum(然后我猜还要删除 ArgumentException)
      【解决方案8】:

      你可以为任何东西创建一个扩展,甚至是object(虽然那是not considered best-practice)。将扩展方法理解为public static 方法。您可以在方法上使用您喜欢的任何参数类型。

      public static class DurationExtensions
      {
        public static int CalculateDistanceBetween(this Duration first, Duration last)
        {
          //Do something here
        }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-11
        • 1970-01-01
        • 2010-12-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多