15

複数の対応する名前を持つ値をToString()呼び出すときに、どの名前が選択されるかを決定するものは何ですか?enum

質問の長い説明は以下のとおりです。

これは、次のいずれかによって一意に決定されるものではないと判断しました。宣言順序; また、名前の長さ。

たとえば、数値が実際の用途 (色の RGB 値など) に直接対応する列挙型が必要だとします。

public enum RgbColor 
{
    Black   = 0x000000,
    Red     = 0xff0000,
    Green   = 0x00ff00,
    Blue    = 0x0000ff,
    White   = 0xffffff
}

これで、この列挙型を呼び出すdefault(RgbColor)と、黒の RGB 値が返されます。デフォルト値を黒にしたくないとしましょう。これは、UI デザイナーが、使用する色について具体的な指示がない場合に「デフォルト」の呼び出しを使用できるようにするためです。今のところ、UI デザイナーが使用するデフォルト値は実際には「青」ですが、これは変更される可能性があります。そのため、列挙型に追加のTextDefault定義を追加すると、次のようになります。

public enum RgbColorWithTextDefaultFirst
{
    TextDefault = 0x0000ff,
    Black   = 0x000000,
    Red     = 0xff0000,
    Green   = 0x00ff00,
    Blue    = 0x0000ff,
    White   = 0xffffff
}

今、私はこれをテストしましたが、呼び出しRgbColorWithTextDefaultFirst.TextDefault.ToString()RgbColorWithTextDefaultFirst.Blue.ToString()両方が「青」を生成することがわかりました。そのため、最後に宣言された名前が以前の宣言の名前を上書きすると考えました。私の仮定をテストするために、私は書きました:

public enum RgbColorWithTextDefaultLast
{
    Black   = 0x000000,
    Red     = 0xff0000,
    Green   = 0x00ff00,
    Blue    = 0x0000ff,
    White   = 0xffffff,
    TextDefault = 0x0000ff 
}

しかし、驚いたことに、RgbColorWithTextDefaultLast.Blue.ToString()そしてRgbColorWithTextDefaultLast.TextDefault.ToString(). 私の次の推測は、名前をアルファベット順に並べ替えて、最初の名前を返すことです。これをテストするには、次のことを試します。

public enum RgbColorWithATextDefaultFirst
{
    ATextDefault = 0x0000ff,
    Black   = 0x000000,
    Red     = 0xff0000,
    Green   = 0x00ff00,
    Blue    = 0x0000ff,
    White   = 0xffffff
}

public enum RgbColorWithATextDefaultLast
{
    Black   = 0x000000,
    Red     = 0xff0000,
    Green   = 0x00ff00,
    Blue    = 0x0000ff,
    White   = 0xffffff,
    ATextDefault = 0x0000ff
}

さて、 、 、 、 の 4 つすべてについてRgbColorWithATextDefaultFirst.ATextDefault.ToString()RgbColorWithATextDefaultFirst.Blue.ToString()RgbColorWithATextDefaultLast.ATextDefault.ToString()RgbColorWithATextDefaultLast.Blue.ToString()」になります。もう一つ特徴的なのは紐の長さです。私の推測では、選択された名前は名前文字列の長さによって決定されます。だから、私のテストはこれらの宣言を使用することです:

public enum RgbColorWithALast
{
    Black   = 0x000000,
    Red     = 0xff0000,
    Green   = 0x00ff00,
    Blue    = 0x0000ff,
    White   = 0xffffff,
    A = 0x0000ff
}

public enum RgbColorWithAFirst
{
    A = 0x0000ff,
    Black   = 0x000000,
    Red     = 0xff0000,
    Green   = 0x00ff00,
    Blue    = 0x0000ff,
    White   = 0xffffff
}

ここで、次のすべてに対してどのような値が得られたかを推測しますRgbColorWithAFirst.A.ToString()RgbColorWithAFirst.Blue.ToString(); RgbColorWithALast.A.ToString()RgbColorWithALast.Blue.ToString()。そうです、「ブルー」です。

この時点で、推測によってこれを決定するものを把握しようとすることをあきらめました。私はリフレクターを開いて、これを調べて理解しようとしていますが、ここで誰かがすでに答えを知っているかどうかを確認するためにここで質問することにしました。複数の対応する名前をToString()持つenum値を呼び出すときに選択されますか?

4

3 に答える 3

6

ここでは行き過ぎかもしれませんが、ソートされた値の二分探索によって決定されると思うので、値の合計数のパリティに依存する可能性があります。両方で別の値を定義することにより、最後の例 ( RgbColorWithAFirstand ) でこれを説明できます。その後、すべての呼び出しから取得します。RgbColorWithALastAToString

私は逆コンパイル (4.0) によってここにたどり着き、最終的に宣言された値のソートされた配列に対するmscorlib呼び出しに到達することに注意しました。Array.BinarySearch当然、バイナリ検索は一致するとすぐに停止するため、2 つの同一の値を切り替える最も簡単な方法は、余分な値を追加して検索ツリーを変更することです。

もちろん、これは実装の詳細であり、依存するべきではありません。あなたの場合DescriptionAttribute、表示値について明示したい列挙値と、次のようなヘルパーメソッドを使用することで、最善のサービスが提供されるように思えます。

public static class EnumExtensions
{
    public static string Description(this Enum value)
    {
        var field = value.GetType().GetField(value.ToString());
        var attribute = Attribute.GetCustomAttribute(
                            field, 
                            typeof (DescriptionAttribute)) 
                        as DescriptionAttribute;

        return attribute == null ? value.ToString() : attribute.Description;
    }
}
于 2012-10-03T15:44:45.853 に答える
3

ドキュメントは、値が重複するとエラーが発生することを警告しています。
重複した値があり、エラーが発生しています-驚くことではありません。

あなたは最初のイコールを取得しています。
平等は価値のみに基づいています。
列挙型が評価される順序を制御することはできません。

コメントで述べたように、列挙型は型の一意の値を期待しています。

列挙型 (C# プログラミング ガイド)

ただし、enum 変数は enum によって定義された値の 1 つだけを保持することが暗黙的に想定されているため、これを行うべきではありません。列挙型の変数に任意の値を割り当てると、エラーが発生するリスクが高くなります。

タイプの値が重複しているリスクの高いエラーの 1 つを発見したようです。

順序を変更することを検討しているため、このエラーを非決定論的であると特徴付けますが、仕様状態に何も指定されていない同じデータは、列挙型入力が順序に依存していることを意味します。OPは異なる順序を異なるデータと見なします。OPの仮定では、これは非決定論的であるとは言えません。type の重複した値によって引き起こされたエラーとして特徴付けるのはまだ公正です。

一意性を暗示する別の参照が期待されます

Enum.GetName

戻り値は文字列です (string[] ではありません)。

Equals は値のみに基づいています。

Enum.Equals

GetName は最初の値に一致します。
それが私の非決定論的定義です。
それらが等しいと見なされている場合、どちらを持っているかをどのように知ることができますか?

疑わしい Microsoft は、オーバーヘッドのために列挙型の値の一意性を強制していません。

OP は、そのタイプの関連付けの指示がない場合、Enum が A 値を A 文字列 (KVP など) に明示的に関連付けることを期待します。
ドキュメントは、その仮定を行うことに対して明示的に警告しています。
Enum がキーと値のペア、クラス、またはストラットのセットとして実装されていることをドキュメントのどこで示していますか?
結果とメソッドは、Enum が緩やかな関連付けを持つ文字列と値の型 (char 以外) であることを示しています。

可能な回避策。

Dictionary は一意の値を必要としません。

public enum RgbColor : byte
{
    Black,
    Red,
    Green,
    Blue,
    White,
    Default
}

static void Main(string[] args)
{
    Dictionary<RgbColor, Int32> ColorRGB = new Dictionary<RgbColor, int>();
    ColorRGB.Add(RgbColor.Black, 0x000000);
    ColorRGB.Add(RgbColor.Default, 0x0000ff);
    ColorRGB.Add(RgbColor.Blue, 0x0000ff);
    ColorRGB.Add(RgbColor.Green, 0x00ff00);
    ColorRGB.Add(RgbColor.White, 0xffffff);

    Debug.WriteLine(ColorRGB[RgbColor.Blue].ToString("X6"));
    Debug.WriteLine(ColorRGB[RgbColor.Default].ToString("X6"));
    Debug.WriteLine(ColorRGB[RgbColor.Black].ToString("X6"));
    Debug.WriteLine(ColorRGB[RgbColor.White].ToString("X6"));
于 2012-10-03T16:50:48.220 に答える
1

動作は未定義です。.NET の特定のバージョンの結果を示すことができたとしても、それは変わる可能性があります。enum.toStringのドキュメントを参照してください。

複数の列挙型メンバーが同じ基になる値を持ち、その基になる値に基づいて列挙型メンバーの名前の文字列表現を取得しようとする場合、メソッドが返す名前についてコードで仮定を行うべきではありません。たとえば、次の列挙は、同じ基になる値を持つ 2 つのメンバー Shade.Gray と Shade.Grey を定義します。

enum Shade { 白 = 0、グレー = 1、グレー = 1、黒 = 2 }

次のメソッド呼び出しは、基になる値が 1 である Shade 列挙のメンバーの名前を取得しようとします。このメソッドは、"Gray" または "Grey" を返すことができます。コードでは、返される文字列について何も仮定しないでください。

string shadeName = ((シェード) 1).ToString();

また、前の段落のドキュメントも参照してください。これには、すべての名前を取得する方法が示されています

于 2012-10-03T18:06:18.950 に答える