枚举的扩展方法,而不是枚举的实例
我有一个枚举我的东西是这样的:
public enum Things { OneThing, AnotherThing }
我想为这个枚举编写一个扩展方法(类似于这里的Prize的答案 ),但是当这个方法在枚举的一个实例上工作时,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();
我们能做得比这更好吗?
扩展方法只适用于实例,所以不能完成,但是有一些精心挑选的类/方法名称和generics,你可以得到一个看起来一样好的结果:
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; } }
那么你可以得到你的select列表像这样:
var list = SelectList.Of<Things>();
海事组织这比Things.ToSelectList()
更好的读取。
没有。
你可以做的最好的是把它放在一个静态类,如下所示:
public static class ThingsUtils { public static SelectList ToSelectList() { ... } }
Aaronaught的答案真的很棒,基于这个我做了以下的实现:
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。
我使用“types”而不是“枚举”来添加扩展名。 然后我可以从方法中获取任何types的列表。 这里它返回string值:
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();
@Aarounaught有一个非常好的答案。 为了扩大他的答案,你甚至可以使其更通用。 我在全球图书馆有这个…
public static IQueryable GetAllEnumValues<T>() { IQueryable retVal = null; Type targetType = typeof(T); if(targetType.IsEnum) { retVal = Enum.GetValues(targetType).AsQueryable(); } return retVal; }
现在,您已经从SelectList类中分离了这个function。 所以你可以在你的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"); } }
在我看来,这是最干净的方式。 为什么?
- 它适用于任何
System.Enum
- 扩展方法本身更清洁。
- 要叫它,你只需添加
new
,这是一个小的折衷(因为它必须有一个实例才能工作。 - 你不会传递
null
,如果你试图用另一种types的话,它实际上不会被编译。
用法:
(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"); }
我认为,最接近的是虚拟的东西,像枚举一样工作,而不是一个枚举。 下面是我想到的 – 在枚举上使用静态方法似乎有很多工作要做,尽pipe我理解它的编程吸引力:
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; } } }