値を変更せずに列挙型のデフォルト値を選択する


208

C#では、値を変更せずに、属性でEnum型を装飾したり、デフォルト値を指定するために何かを行ったりすることはできますか?必要な数は何らかの理由で石で設定される可能性があり、デフォルトを引き続き制御できると便利です。

enum Orientation
{
    None = -1,
    North = 0,
    East = 1,
    South = 2,
    West = 3
}

Orientation o; // Is 'North' by default.

int?、double?などのデフォルト値を変更できますか?
AR

2
@AR過去に害はありませんが、列挙型を抽象型でints と比較することは意味がありません。単にそれらがたまたま数値型として実装されているからです。enumを文字列として実装することもできますが、その有用性は変わりません。ここでの答えは、C#言語の表現力の制限と考えています。この制限は、「制限されたセットから値を区別する」という考えに固有のものではありません。
jpaugh、

1
@jpaugh enumをintと「抽象的に」比較しているのではありません。デフォルトを変更しても意味がない他のデータ(文字列や他の参照を含む)タイプの例を示します。これは制限ではなく、設計上の機能です。一貫性はあなたの友達です:)
AR

@ARポイントが取得されました。私は、enumsを型レベルの構成体、具体的には合計型として考えるのにあまりにも多くの時間を費やしていると思います(つまり、ここでを参照してください。そのような考え方から、列挙型が値を共有することは不可能であり、実際に、この抽象化は、デフォルトの0が特定の列挙型に対して有効である場合とそうでない場合があり、単純にすべての列挙型に角張っていると考えるとばらばらになります。
jpaugh

はい、私は差別された労働組合に精通しています。C#の列挙型はそうではないので、そのような高い(そして正しくない)レベルでそれらを考えることが役立つかどうかはわかりません。「合計型」には確かにその利点がありますが、そうであり、列挙型でもあります(適切な値が提供されている場合)。例:myColor = Colors.Red | Colors.Blue。私の主なポイントは、C#の合計型が必要な場合は、列挙型の概念を再利用するのではなく、C#を作成することです。
AR、

回答:


349

enum(実際には任意の値タイプ)のデフォルトは0ですenum。これがその値に対して有効な値でなくてもです。変更できません。


13
質問を言い換えて、intのデフォルト値が42であることを確認します。どのように聞こえるかを考えてみてください...メモリは、実行前にランタイムによってブランクにされ、列挙型は構造体です
ShuggyCoUk

3
@DougS 1.いいえ、しかしあなたが間違っていたと認めることは間違っています。2.彼はコメントの賛成票からいかなる評判も獲得しませんでした。
Aske B.

7
コメントはこの回答に疑いを抱かせたので、私はそれをテストし、この回答が間違いなく正しいことを確認しました。
Ian Newson 2013年

1
@JamesCurranしかし、列挙型に0の値を使用しないと、「タイプ 'System.NullReferenceException'の例外がMyProjectName.dllで発生しましたが、ユーザーコードでは処理されませんでした。追加情報:オブジェクト参照がオブジェクトのインスタンスに設定されていません。」エラー。それを修正するには?注:列挙型の説明を表示するために拡張メソッドを使用していますが、このページで
Jack

64

列挙型のデフォルト値はゼロです。したがって、1つの列挙子をデフォルト値に設定する場合は、その1をゼロに設定し、他のすべての列挙子をゼロ以外に設定します(値がゼロの最初の列挙子は、列挙子が複数ある場合、その列挙型のデフォルト値になります)値がゼロの場合)。

enum Orientation
{
    None = 0, //default value since it has the value '0'
    North = 1,
    East = 2,
    South = 3,
    West = 4
}

Orientation o; // initialized to 'None'

列挙子が明示的な値を必要としない場合は、最初の列挙子がデフォルトの列挙子になりたいものであることを確認してください。「デフォルトでは、最初の列挙子の値は0であり、連続する各列挙子の値は1.」(C#リファレンス

enum Orientation
{
    None, //default value since it is the first enumerator
    North,
    East,
    South,
    West
}

Orientation o; // initialized to 'None'

38

ゼロが適切なデフォルト値として機能しない場合は、コンポーネントモデルを使用して列挙型の回避策を定義できます。

[DefaultValue(None)]
public enum Orientation
{
     None = -1,
     North = 0,
     East = 1,
     South = 2,
     West = 3
 }

public static class Utilities
{
    public static TEnum GetDefaultValue<TEnum>() where TEnum : struct
    {
        Type t = typeof(TEnum);
        DefaultValueAttribute[] attributes = (DefaultValueAttribute[])t.GetCustomAttributes(typeof(DefaultValueAttribute), false);
        if (attributes != null &&
            attributes.Length > 0)
        {
            return (TEnum)attributes[0].Value;
        }
        else
        {
            return default(TEnum);
        }
    }
}

そして、あなたは呼び出すことができます:

Orientation o = Utilities.GetDefaultValue<Orientation>();
System.Diagnostics.Debug.Print(o.ToString());

注:ファイルの先頭に次の行を含める必要があります。

using System.ComponentModel;

これは、列挙型の実際のC#言語のデフォルト値を変更しませんが、望ましいデフォルト値を示す(そして取得する)方法を提供します。


申し訳ありませんが、機能しません。さらに情報を追加できますか?System.ComponentModelを使用して行を追加する必要があります。その後、UtilitiesクラスにGetDefaultEnum()関数を記述します。使用している.netのバージョンは何ですか?
David

3
+1は、コンポーネントモデル属性とクリーンソリューションを再利用します。elseステートメントの最終行を次のように変更することをお勧めしますreturn default(TEnum);Enum.GetValues(...).***第一に、遅い呼び出しを減らします、第二に(そしてより重要なことですが)、それは列挙型ではなく、あらゆるタイプに対して一般的です。さらに、列挙型のみに使用されるコードを制限しないため、これにより、非列挙型に対して使用された場合の潜在的な例外が実際に修正されます。
Ivaylo Slavov

1
これは、質問のコンテキストでのデフォルト値属性の誤用である可能性があります。尋ねられる質問は、自動的に初期化された値に関するものであり、提案されたソリューションでは変更されません。この属性は、ビジュアルデザイナーのデフォルトが初期値と異なることを意図しています。ビジュアルデザイナーに質問する人からの言及はありません。
David Burg

2
MSDNドキュメントには、ComponentModelまたはDefaultAttributeが「ビジュアルデザイナー」のみの機能であることは本当にありません。受け入れられた答えが述べるように。簡単に言えば、列挙型のデフォルト値を0以外の値に再定義するのは「いいえ、不可能」です。この回答は回避策です。
David

17

列挙型のデフォルトは、ゼロに等しい列挙型です。これが属性やその他の方法で変更できるとは思いません。

(MSDNは言う:「列挙Eのデフォルト値は、式(E)0によって生成された値です。」)


13
厳密に言えば、この値を列挙する必要はありません。デフォルトはゼロのままです。
Marc Gravell

11

できませんが、必要に応じて、いくつかのトリックを実行できます。:)

    public struct Orientation
    {
        ...
        public static Orientation None = -1;
        public static Orientation North = 0;
        public static Orientation East = 1;
        public static Orientation South = 2;
        public static Orientation West = 3;
    }

この構造体の単純な列挙型としての使用。 トリック自体を使用するために
デフォルトでpa == Orientation.East(または必要な任意の値)を作成できる場所では
、コードによってintから変換する必要があります。
そこで実装:

        #region ConvertingToEnum
        private int val;
        static Dictionary<int, string> dict = null;

        public Orientation(int val)
        {
            this.val = val;
        }

        public static implicit operator Orientation(int value)
        {
            return new Orientation(value - 1);
        }

        public static bool operator ==(Orientation a, Orientation b)
        {
            return a.val == b.val;
        }

        public static bool operator !=(Orientation a, Orientation b)
        {
            return a.val != b.val;
        }

        public override string ToString()
        {
            if (dict == null)
                InitializeDict();
            if (dict.ContainsKey(val))
                return dict[val];
            return val.ToString();
        }

        private void InitializeDict()
        {
            dict = new Dictionary<int, string>();
            foreach (var fields in GetType().GetFields(BindingFlags.Public | BindingFlags.Static))
            {
                dict.Add(((Orientation)fields.GetValue(null)).val, fields.Name);
            }
        } 
        #endregion

暗黙の変換演算子では必要ですがvalue + 1、それ以外の場合はdefault(Orientation)戻り値Eastです。また、コンストラクターをプライベートにします。良いアプローチ。
nawfal

10

役立つかもしれないもう1つの方法-ある種の「エイリアス」を使用する。例えば:

public enum Status
{
    New = 10,
    Old = 20,
    Actual = 30,

    // Use Status.Default to specify default status in your code. 
    Default = New 
}

1
提案は適切ですが、他の回答ですでに述べたように、列挙型のデフォルト値はゼロです。あなたの場合、式はの値を持つためStatus s = default(Status);、ステータスメンバーにはなりません。列挙型は整数にキャストできるため、後者は直接書き込むことができますが、フレームワークは列挙型が常に有効なメンバーに逆シリアル化されることを確認するため、逆シリアル化中に失敗します。行をに変更すると、コードは完全に有効になります。s(Staus) 0New = 10New = 0
Ivaylo Slavov

1
はい。新規= 0が機能します。個人的には、列挙型メンバーを明示的に設定しないようにします。
ドミトリーパブロフ

7

実際、enumのデフォルトはの最初の要素enumです0

だから例えば:

public enum Animals
{
    Cat,
    Dog,
    Pony = 0,
}
//its value will actually be Cat not Pony unless you assign a non zero value to Cat.
Animals animal;

9
ただし、その場合、「ポニー」は「猫」です(たとえば、Console.WriteLine(Animals.Pony);「猫」と印刷されます)
James Curran

16
実際には、次のいずれかを行う必要があります。値を指定しないか、すべての値を指定するか、最初に定義されたメンバーの値のみを指定します。ここで何が起こるかというと、猫には値がなく、最初の値なので、自動的に0に設定されます。犬には値がなく、自動的にPreviousValue + 1、つまり1に設定されます。Poneyには値があり、値はそのままにします。したがって、Cat = Pony = 0、Dog = 1です。{Cat、Dog、Pony = 0、Frog}がある場合、Dog = Frog = 1
user276648

4

The default value of enum is the enummember equal to 0 or the first element(if value is not specified) ...しかし、プロジェクトで列挙型を使用して重大な問題に直面し、以下のことを実行して克服しました...私のニーズがクラスレベルに関連していた...

    class CDDtype
    {
        public int Id { get; set; }
        public DDType DDType { get; set; }

        public CDDtype()
        {
            DDType = DDType.None;
        }
    }    


    [DefaultValue(None)]
    public enum DDType
    {       
        None = -1,       
        ON = 0,       
        FC = 1,       
        NC = 2,       
        CC = 3
    }

期待される結果を得る

    CDDtype d1= new CDDtype();
    CDDtype d2 = new CDDtype { Id = 50 };

    Console.Write(d1.DDType);//None
    Console.Write(d2.DDType);//None

次に、値がDBからのものである場合....このシナリオではOK ...以下の関数に値を渡して、値を列挙型に変換します...以下の関数はさまざまなシナリオを処理し、それは一般的です...とても早い ..... :)

    public static T ToEnum<T>(this object value)
    {
        //Checking value is null or DBNull
        if (!value.IsNull())
        {
            return (T)Enum.Parse(typeof(T), value.ToStringX());
        }

        //Returanable object
        object ValueToReturn = null;

        //First checking whether any 'DefaultValueAttribute' is present or not
        var DefaultAtt = (from a in typeof(T).CustomAttributes
                          where a.AttributeType == typeof(DefaultValueAttribute)
                          select a).FirstOrNull();

        //If DefaultAttributeValue is present
        if ((!DefaultAtt.IsNull()) && (DefaultAtt.ConstructorArguments.Count == 1))
        {
            ValueToReturn = DefaultAtt.ConstructorArguments[0].Value;
        }

        //If still no value found
        if (ValueToReturn.IsNull())
        {
            //Trying to get the very first property of that enum
            Array Values = Enum.GetValues(typeof(T));

            //getting very first member of this enum
            if (Values.Length > 0)
            {
                ValueToReturn = Values.GetValue(0);
            }
        }

        //If any result found
        if (!ValueToReturn.IsNull())
        {
            return (T)Enum.Parse(typeof(T), ValueToReturn.ToStringX());
        }

        return default(T);
    }

与えられた質問に意図的に答えない場合は-1。これは明らかな宿題の問題ではありません。故意に答えない唯一のケースです。
Xynariz 2014

1
@Xynariz ..申し訳ありませんが、私のコメントは誤って否定的でした。私の意図は別の方法で解決策を提供することだったので...コメントを変更しました...:D
Moumit

2

列挙型のデフォルト値は0です。

  • デフォルトでは、最初の列挙子の値は0で、後続の各列挙子の値は1ずつ増加します。

  • " 値タイプenumには、式(E)0によって生成された値が含まれます。ここで、Eはenum識別子です。 "

ここでC#enumのドキュメントを確認でき、C#のデフォルト値の表のドキュメントをここで確認できます


1

Default enumを最小値のenumとして定義すると、これを使用できます。

public enum MyEnum { His = -1, Hers = -2, Mine = -4, Theirs = -3 }

var firstEnum = ((MyEnum[])Enum.GetValues(typeof(MyEnum)))[0];

firstEnum == Mine.

これは、列挙型の値がゼロであることを想定していません。


0

デフォルトは定義の最初のものです。例えば:

public enum MyEnum{His,Hers,Mine,Theirs}

Enum.GetValues(typeOf(MyEnum)).GetValue(0);

これは戻ります His


はは; 「デフォルト値」はゼロです。だが!彼は、デフォルト値「ゼロ」はたまたま最初に名前が付けられた値のデフォルトシンボルであると言います。!言い換えれば、言語はあなたの代わりにデフォルトを選択します。これはちょうどゼロが整数のデフォルト値であることも起こります
。lol

0
enum Orientations
{
    None, North, East, South, West
}
private Orientations? _orientation { get; set; }

public Orientations? Orientation
{
    get
    {
        return _orientation ?? Orientations.None;
    }
    set
    {
        _orientation = value;
    }
}

プロパティをnullに設定すると、取得時にOrientations.Noneを返します。プロパティ_orientationはデフォルトではnullです。


-5
[DefaultValue(None)]
public enum Orientation
{
    None = -1,
    North = 0,
    East = 1,
    South = 2,
    West = 3
}

次に、コードで使用できます

public Orientation GetDefaultOrientation()
{
   return default(Orientation);
} 

14
/!\ WRONG /!\ DefaultValueAttributeは実際に値を設定するのではなく、情報提供のみを目的としています。次に、列挙型、フィールド、プロパティなどがその属性を持っているかどうかを確認するのはあなた次第です。PropertyGridはそれを使用して、右クリックして「リセット」を選択できるようにします。デフォルト値を使用していない場合も、テキストは太字で表示されますが、プロパティを手動でデフォルト値に設定する必要があります。
user276648 '14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.