枚举扩展方法

54
在vs2008中,是否可以编写一个扩展方法,使其适用于任何枚举类型?
我知道你可以针对特定枚举类型编写扩展方法,但我想能够使用单个扩展方法来处理每个枚举类型。这是可能的吗?

这个回答解决了您的问题吗?对枚举的扩展方法,而不是枚举实例 - malat
7个回答

81

是的,只需针对基本的 Enum 类型编写代码,例如:

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

缺点是您可能需要执行一些比较恶心的工作,例如使用Enum.GetUnderlyingType查找实际基本类型,进行强制类型转换,根据enum的基本类型走不同的分支路线,但是您可以找到一些很好的用途(例如我们有适用于所有枚举类型的IsOneOfIsCombinationOf方法)。

PS:在编写该方法时,请记住,虽然不建议,但您可以将floatdouble用作枚举类型的基本类型,因此您还需要针对这些类型以及无符号值进行一些特殊处理。


你给出的例子正是我想要做的,甚至连名字都一样。 :) - Eric Haskins
4
在哪种编程语言中可以将float和double作为枚举类型的基础类型?在C#中不能这样做-您会得到错误CS1008:期望类型为byte、sbyte、short、ushort、int、uint、long或ulong。 - Jon Skeet
3
我知道支持该功能的唯一语言是CIL。我并没有试过来证明它是否可行,因为似乎这是一个一般不好的想法,但请看Rico在这里底部的评论:http://en.csharp-online.net/.NET_Type_Design_Guidelines%E2%80%94Enum_Design - Greg Beech
@Luis - 不,你需要C# 3.0语法来使用扩展方法,而这在VS2005中是不支持的。 - Greg Beech
@GregBeech:你能帮忙解决这个问题吗?https://dev59.com/yXXYa4cB1Zd3GeqP63xL - Jimbo

18

提供一份很好的枚举扩展方法示例,可以实现不区分大小写的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);
}

以下是我访问的两个网站,以帮助编写此代码:

枚举类型的不区分大小写的 TryParse

枚举类型的扩展方法


8
只是作为一个注脚,在.NET 4及以上版本中,Enum.TryParse方法有一个重载可以指定大小写敏感性:http://msdn.microsoft.com/zh-cn/library/dd991317(v=vs.100).aspx - KevD

18

可以。目标扩展类型是Enum类型。在C#中,可以这样做:

public static void EnumExtension(this Enum e)
{
}

或者在VB中这样写:

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

9
这是另一个例子 - 在我看来比创建和初始化临时变量更好。
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); 
} 

1
尽管default(TestEnum)创建的是一个匿名且立即进行垃圾回收的实例,但您仍然在创建枚举的临时实例。值得指出的是,扩展方法如果没有正在扩展的实例就无法正常工作,因此我们能够做到的最接近的方法是实例化枚举类型本身并从该类型进行扩展方法。请参阅https://dev59.com/D3E95IYBdhLWcg3wKq6q,了解一种有趣的实现方式。 - MushinNoShin

4
您也可以按照以下方式实现转换方法:
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 - John Alexiou

2
有时需要根据枚举的名称或值将其从一个枚举类型转换为另一个。以下是如何使用扩展方法实现较好的转换方式:
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)));
    }
}

1
另一个制作枚举扩展的例子 - 但这次它返回输入的枚举类型。
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();

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