web-dev-qa-db-ja.com

列挙のインスタンスではなく列挙の拡張メソッド

私は私のようなものの列挙を持っています:

public enum Things
{
   OneThing,
   AnotherThing
}

この列挙型の拡張メソッドを記述したいと思います(同様の Priseの回答 )。ただし、このメソッドは列挙型のインスタンスで機能しますが、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();

それ以上のことはできますか?

44
Jamezor

拡張メソッドはインスタンスでのみ機能するため、実行できませんが、適切に選択されたクラス/メソッド名とジェネリックスを使用すると、見栄えのよい結果を生成できます。

_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()よりもはるかに読みやすくなります。

72
Aaronaught

番号。

あなたができる最善のことは、次のようにそれを静的クラスに置くことです:

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

アーロノートの答えは本当に素晴らしいです。それに基づいて、私は次の実装を行いました。

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を返すことができます。

4
qqbenq

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

拡張機能を追加するには、「列挙型」の代わりに「タイプ」を使用します。次に、メソッドから任意のタイプのリストを取得できます。ここでは文字列値を返します:

    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
Bahram

私の意見では、これが最もクリーンな方法です。どうして?

  • それは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
toddmo