Метод расширения при перечислении, а не экземпляр перечисления - PullRequest
44 голосов
/ 11 марта 2010

У меня есть перечисление для моих вещей, например:

public enum Things
{
   OneThing,
   AnotherThing
}

Я хотел бы написать метод расширения для этого перечисления (аналогично ответ Призе здесь ), но пока этот метод работает на экземпляре перечисления , ala

Things thing; var list = thing.ToSelectList();

Я бы хотел, чтобы он работал с фактическим перечислением вместо:

var list = Things.ToSelectList();

Я мог бы просто сделать

var list = default(Things).ToSelectList();

Но мне не нравится, как это выглядит :)

Я приблизился с помощью следующего метода расширения:

public static SelectList ToSelectList(this Type type)
{
   if (type.IsEnum)
   {
      var values = from Enum e in Enum.GetValues(type)
                   select new { ID = e, Name = e.ToString() };
      return new SelectList(values, "Id", "Name");
   }
   else
   {
      return null;
   }
}

Используется так:

var list = typeof(Things).ToSelectList();

Можем ли мы сделать что-то лучше?

Ответы [ 7 ]

72 голосов
/ 11 марта 2010

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

public class SelectList
{
    // Normal SelectList properties/methods go here

    public static SelectList Of<T>()
    {
        Type t = typeof(T);
        if (t.IsEnum)
        {
            var values = from Enum e in Enum.GetValues(type)
                         select new { ID = e, Name = e.ToString() };
            return new SelectList(values, "Id", "Name");
        }
        return null;
    }
}

Тогда вы можете получить список выбора следующим образом:

var list = SelectList.Of<Things>();

IMO это выглядит намного лучше, чем Things.ToSelectList().

5 голосов
/ 11 марта 2010

номер

Лучшее, что вы можете сделать, это поместить его в статический класс, например:

public static class ThingsUtils { 
    public static SelectList ToSelectList() { ... }
}
4 голосов
/ 27 марта 2014

Ответ Ааронаута действительно велик, исходя из того, что я сделал следующую реализацию:

public class SelectList
{
    public static IEnumerable<Enum> Of<T>() where T : struct, IConvertible
    {
        Type t = typeof(T);
        if (t.IsEnum)
        {
            return Enum.GetValues(t).Cast<Enum>();
        }
        throw new ArgumentException("<T> must be an enumerated type.");
    }
}

На мой взгляд, это немного безопаснее, поскольку вы можете - почти - вызывать его только с помощью Enums, и, конечно, вместо броска вы можете просто вернуть null, если вы хотите версию без исключений.

1 голос
/ 25 января 2013

Я использую «Тип» вместо «Enum», чтобы добавить расширение. Тогда я могу получить любой тип списка обратно из метода. Здесь он возвращает строковые значения:

    public static string[] AllDescription(this Type enumType)
    {
        if (!enumType.IsEnum) return null;

        var list = new List<string>();
        var values = Enum.GetValues(enumType);

        foreach (var item in values)
        {
            // add any combination of information to list here:
            list.Add(string.Format("{0}", item));

            //this one gets the values from the [Description] Attribute that I usually use to fill drop downs
            //list.Add(((Enum) item).GetDescription());
        }

        return list.ToArray();
    }

Позже я мог бы использовать этот синтаксис, чтобы получить то, что я хочу:

var listOfThings = typeof (Things).AllDescription();
1 голос
/ 12 декабря 2011

@ У Аарона есть очень хороший ответ. Чтобы расширить его ответ, вы также можете сделать его более общим. У меня есть это в глобальной библиотеке ...

public static IQueryable GetAllEnumValues<T>()
{
    IQueryable retVal = null;

    Type targetType = typeof(T);
    if(targetType.IsEnum)
    {
        retVal = Enum.GetValues(targetType).AsQueryable();
    }

    return retVal;
}

Теперь вы отключили эту функцию из класса SelectList. Так что вы можете вызывать это в ваших методах SelectList или где-то еще.

public class SelectList
{
    public static SelectList Of<T>
    {
        IQueryable enumValues = GetAllEnumValues<T>();
        var values = 
            from Enum e in enumValues
            select new { ID = e, Name = e.ToString() };
        return new SelectList(values, "Id", "Name");
    }
}
0 голосов
/ 23 апреля 2016

На мой взгляд, это самый чистый способ. Почему?

  • Работает для любого System.Enum
  • Сам метод расширения чище.
  • Чтобы вызвать его, просто добавьте new, и это небольшой компромисс (потому что для работы ему нужен экземпляр.
  • Вы не передаете null, и он буквально не скомпилируется, если вы попытаетесь использовать его с другим типом.

Использование:

(new Things()).ToSelectList()

Метод расширения:

[Extension()]
public SelectList ToSelectList(System.Enum source)
{
    var values = from Enum e in Enum.GetValues(source.GetType)
                select new { ID = e, Name = e.ToString() };
    return new SelectList(values, "Id", "Name");    
}
0 голосов
/ 30 мая 2013

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

    public class PseudoEnum
{
    public const int FirstValue = 1;
    private static PseudoEnum FirstValueObject = new PseudoEnum(1);

    public const int SecondValue = 2;
    private static PseudoEnum SecondValueObject = new PseudoEnum(2);

    private int intValue;

    // This prevents instantation; note that we cannot mark the class static
    private PseudoEnum() {}

    private PseudoEnum(int _intValue)
    {
        intValue = _intValue;
    }

    public static implicit operator int(PseudoEnum i)
    {
        return i.intValue;
    }

    public static implicit operator PseudoEnum(int i)
    {
        switch (i)
        {
            case FirstValue :
                return FirstValueObject;
            case SecondValue :
                return SecondValueObject;
            default:
                throw new InvalidCastException();
        }
    }

    public static void DoSomething(PseudoEnum pe)
    {
        switch (pe)
        {
            case PseudoEnum.FirstValue:
                break;
            case PseudoEnum.SecondValue:
                break;
        }
    }

}
...