枚举的扩展方法,而不是枚举的实例

时间:2010-03-11 02:19:39

标签: c# enums extension-methods

我对我的事情进行了枚举:

public enum Things
{
   OneThing,
   AnotherThing
}

我想为此枚举编写一个扩展方法(类似于Prise's answer here),但该方法适用于枚举的实例,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 个答案:

答案 0 :(得分:72)

扩展方法仅适用于实例,因此无法完成,但通过一些精心选择的类/方法名称和泛型,您可以生成看起来同样好的结果:

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()读得好很多。

答案 1 :(得分:5)

没有

你能做的最好的就是把它放在一个静态类上,如下所示:

public static class ThingsUtils { 
    public static SelectList ToSelectList() { ... }
}

答案 2 :(得分:4)

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。

答案 3 :(得分:1)

@Aaronaught有一个非常好的答案。为了扩展他的答案,你甚至可以使它更通用。我在全球图书馆有这个......

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");
    }
}

答案 4 :(得分:1)

我使用'Type'代替'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();

答案 5 :(得分:0)

在我看来,这是最干净的方式。为什么呢?

  • 适用于任何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");    
}

答案 6 :(得分:-1)

我认为,你最接近的就是把一些东西弄得像一个枚举而不是一个人。这就是我想出来的东西 - 虽然我确实理解了它的编程吸引力,但是在枚举中使用静态方法看起来似乎很多工作:

    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;
        }
    }

}