【问题标题】:Enumeration extension methods枚举扩展方法
【发布时间】:2010-09-21 13:16:31
【问题描述】:

在vs2008中,是否可以编写适用于任何枚举的扩展方法。

我知道您可以针对特定枚举编写扩展方法,但我希望能够使用单个扩展方法来处理每个枚举。这可能吗?

【问题讨论】:

标签: .net enums extension-methods enumeration


【解决方案1】:

是的,只需针对基本 Enum 类型进行编码,例如

public static void Something(this Enum e)
{
    // code here
}

不利的一面是,您最终可能会做一些非常讨厌的事情,例如使用 Enum.GetUnderlyingType 查找真正的基本类型、强制转换以及根据枚举的基本类型进入不同的分支,但是您可以找到一些好的用途(例如,我们有适用于所有枚举的 IsOneOfIsCombinationOf 方法)。

PS:请记住,在编写方法时,尽管不建议您使用 floatdouble 作为枚举的基本类型,因此您需要一些特殊情况以及无符号值。

【讨论】:

  • 你给出的例子正是我想做的,甚至是同名。 :)
  • @Greg:在哪种语言中,您可以使用 float 和 double 作为枚举的基础类型?你不能在 C# 中 - 你得到错误 CS1008: Type byte, sbyte, short, ushort, int, uint, long, or ulong expected
  • 我所知道的唯一支持它的语言是 CIL。我实际上并没有尝试过证明这一点,因为这似乎是一个普遍的坏主意,但请参阅 Rico 在底部附近的评论:en.csharp-online.net/…
  • @Luis - 不,扩展方法需要 C# 3.0 语法,VS2005 不支持。
  • @GregBeech:你能帮忙写这篇文章吗? stackoverflow.com/q/18145161/175893
【解决方案2】:

是的,你可以。目标扩展类型是Enum 类型。在 C# 中,这将作为:

public static void EnumExtension(this Enum e)
{
}

或在 VB 中这样:

<Extension()> _
Public Sub EnumExtension(ByVal s As Enum)
End Sub

【讨论】:

    【解决方案3】:

    仅供参考,这是我已经能够使用的枚举扩展方法的一个很好的例子。它为枚举实现了一个不区分大小写的 TryParse() 函数:

    public static class ExtensionMethods
    {
        public static bool TryParse<T>(this Enum theEnum, string strType, 
            out T result)
        {
            string strTypeFixed = strType.Replace(' ', '_');
            if (Enum.IsDefined(typeof(T), strTypeFixed))
            {
                result = (T)Enum.Parse(typeof(T), strTypeFixed, true);
                return true;
            }
            else
            {
                foreach (string value in Enum.GetNames(typeof(T)))
                {
                    if (value.Equals(strTypeFixed, 
                        StringComparison.OrdinalIgnoreCase))
                    {
                        result = (T)Enum.Parse(typeof(T), value);
                        return true;
                    }
                }
                result = default(T);
                return false;
            }
        }
    }
    

    您可以通过以下方式使用它:

    public enum TestEnum
    {
        A,
        B,
        C
    }
    
    public void TestMethod(string StringOfEnum)
    {
        TestEnum myEnum;
        myEnum.TryParse(StringOfEnum, out myEnum);
    }
    

    以下是我访问的两个网站以帮助提出此代码:

    Case Insensitive TryParse for Enums

    Extension methods for Enums

    【讨论】:

    【解决方案4】:

    这是另一个示例 - 恕我直言,这比创建和初始化临时变量更好。

    public static class ExtensionMethods 
    {
        public static void ForEach(this Enum enumType, Action<Enum> action)
        {
            foreach (var type in Enum.GetValues(enumType.GetType()))
            {
                action((Enum)type);
            }
        }
    }
    
    public enum TestEnum { A,B,C } 
    public void TestMethod() 
    {
        default(TestEnum).ForEach(Console.WriteLine); 
    } 
    

    【讨论】:

    • 您仍在default(TestEnum) 中创建枚举的临时实例,尽管它是匿名的并立即用于垃圾收集。值得指出的是,扩展方法在没有被扩展的实例的情况下根本无法工作,所以我们能得到的最接近的方法是实例化枚举本身的类型,并从该类型中获得扩展方法。请参阅stackoverflow.com/questions/2422113/… 了解实现此目的的有趣方式。
    【解决方案5】:

    你也可以如下实现转换方法:

    public static class Extensions
    {
        public static ConvertType Convert<ConvertType>(this Enum e)
        {
            object o = null;
            Type type = typeof(ConvertType);
    
            if (type == typeof(int))
            {
                o = Convert.ToInt32(e);
            }
            else if (type == typeof(long))
            {
                o = Convert.ToInt64(e);
            }
            else if (type == typeof(short))
            {
                o = Convert.ToInt16(e);
            }
            else
            {
                o = Convert.ToString(e);
            }
    
            return (ConvertType)o;
        }
    }
    

    这是一个示例用法:

    int a = MyEnum.A.Convert<int>();
    

    【讨论】:

    • 我认为每个Enum 都实现了IConvertible
    【解决方案6】:

    有时需要根据枚举的名称或值从一个枚举转换为另一个枚举。以下是如何使用扩展方法很好地完成它:

    enum Enum1 { One = 1, Two = 2, Three = 3 };
    enum Enum2 { Due = 2, Uno = 1 };
    enum Enum3 { Two, One };
    
    Enum2 e2 = Enum1.One.ConvertByValue<Enum2>();
    Enum3 e3 = Enum1.One.ConvertByName<Enum3>();
    Enum3 x2 = Enum1.Three.ConvertByValue<Enum3>();
    
    public static class EnumConversionExtensions
    {
        public static T ConvertByName<T>(this Enum value)
        {
            return (T)Enum.Parse(typeof(T), Enum.GetName(value.GetType(), value));
        }
    
        public static T ConvertByValue<T>(this Enum value)
        {
            return (T)((dynamic)((int)((object)value)));
        }
    }
    

    【讨论】:

      【解决方案7】:

      另一个制作 Enum 扩展的例子 - 但这次它返回输入的枚举类型。

      public static IEnumerable<T> toElementsCollection<T>(this T value) where T : struct, IConvertible
          {
              if (typeof(T).IsEnum == false) throw new Exception("typeof(T).IsEnum == false");
      
              return Enum.GetValues(typeof(T)).Cast<T>();
          }
      

      使用示例:

      public enum TestEnum { A,B,C };
      
      TestEnum.A.toElementsCollection();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-08-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多