Методы расширения перечисления - PullRequest
54 голосов
/ 10 ноября 2008

В vs2008 можно ли написать методы расширения, которые будут применяться к любому перечислению.

Я знаю, что вы можете написать методы расширения для конкретного перечисления, но я хочу иметь возможность для каждого перечисления, используя один метод расширения. Это возможно?

Ответы [ 7 ]

81 голосов
/ 10 ноября 2008

Да, просто код против базового типа Enum, например,

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

Обратной стороной является то, что вы, вероятно, в конечном итоге будете делать довольно неприятные вещи, такие как поиск реального базового типа с использованием Enum.GetUnderlyingType, приведение и переход к различным веткам в зависимости от того, какой базовый тип перечисление есть, но вы можете найти несколько хороших вариантов его использования (например, у нас есть методы IsOneOf и IsCombinationOf, которые применяются ко всем перечислениям).

PS: Помните, когда пишете метод, который, хотя и не рекомендуется, вы можете использовать float и double в качестве базовых типов для перечислений, так что вам потребуются некоторые особые случаи для них, а также для значений без знака. *

18 голосов
/ 18 июня 2009

К вашему сведению Вот отличный пример метода Enum Extension, который я смог использовать. Реализует регистрозависимую функцию 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 для перечислений

Методы расширения для Enums

18 голосов
/ 10 ноября 2008

Да, вы можете. Тип целевого расширения имеет тип Enum. В C # это будет сделано как:

public static void EnumExtension(this Enum e)
{
}

или как это в VB:

<Extension()> _
Public Sub EnumExtension(ByVal s As Enum)
End Sub
9 голосов
/ 12 января 2012

Вот еще один пример - ИМХО также приятнее, чем необходимость создания и инициализации временной переменной.

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); 
} 
4 голосов
/ 25 июня 2012

Вы также можете реализовать метод преобразования следующим образом:

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>();
2 голосов
/ 31 октября 2013

Иногда необходимо выполнить преобразование из одного перечисления в другое, основываясь на имени или значении перечисления. Вот как это можно сделать с помощью методов расширения:

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 голос
/ 21 июля 2015

Еще один пример расширения Enum - но на этот раз он возвращает тип входного 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();
...