15

数値を表すために暗黙の列挙型フィールドを使用することは、必然的に悪い習慣ですか?

ユースケースは次のとおりです。16進数を表す簡単な方法が必要です。C#列挙型は整数に基づいているため、自然に一致しているように見えます。値を明示的に検証する必要があるため、 acharまたはhereは好きではありません。string列挙型の問題は、数字[0-9]が有効なフィールド識別子ではないことです(正当な理由があります)。0-9数字は暗黙的に存在するため、数字を宣言する必要がないことに気づきました。

したがって、私の16進数の列挙型は次のようになります。

public enum Hex : int { 
    A = 10,
    B = 11,
    C = 12,
    D = 13,
    E = 14,
    F = 15
}

だから、私は書くことができTuple<Hex,Hex> r = Tuple.Create(Hex.F,(Hex)1);、私にr.Item1.ToString() + r.Item2.ToString()「F1」を与えるでしょう。基本的に、私の質問はToString()、数値定数の値が列挙型フィールドに名前を付けたいものである場合、宣言を完全に省略することがなぜ問題になるのかということです。

列挙型としての代替表現では、次のような接頭辞を付けてフィールドを宣言できます。

public enum Hex : int {
    _0 = 0,
    _1 = 1,
    _2 = 2,
    _3 = 3,
    _4 = 4,
    _5 = 5,
    _6 = 6,
    _7 = 7,
    _8 = 8,
    _9 = 9, 
    A = 10,
    B = 11,
    C = 12,
    D = 13,
    E = 14,
    F = 15
}

問題は、上記の例では「F1」ではなく「F_1」が表示されることです。明らかに、これは簡単に修正できます。私が考慮していない暗黙のアプローチに追加の問題があるかどうか疑問に思います。

4

6 に答える 6

13

それはあなたのコードを読む人々にとって驚くべき巧妙なトリックなので、それは悪い習慣です。それが実際に機能したことに驚いた、それは私にwtfと言わせた。コード品質の唯一の有効な測定値を覚えておいてください。

ここに画像の説明を入力してください

巧妙なトリックは、他の人が読んで維持することを目的としたコードには属していません。数値を16進数として出力する場合は、通常の方法を使用して16進数の文字列に変換します。String.Format("{0:X}", value)

于 2012-10-09T02:37:22.457 に答える
7

これは、16 進数を処理する根本的に壊れた方法です。16 進数は、ヒューマン インターフェイスの詳細です。これは常に、数値の表現であるstringです。同様に、「1234」は値 1234 の表現です。16 進数で表現するとたまたま「4D2」になりますが、プログラム内の数値は依然として 1234 です。プログラムは数値だけに関心を持ち、表現には決して関心を払うべきではありません。

数値を 16 進数に変換するのは、数値を人間の目に表示する場合のみです。ToString("X") で簡単に実行できます。NumberStyles.HexNumber を使用して、TryParse() で人間の入力から解析します。入力と出力、他のポイントでは 16 進数を扱う必要はありません。

于 2012-10-05T00:15:08.680 に答える
3

structforを定義しますHexDigitHexDigit「A」を「F」に静的定数 (または静的読み取り専用フィールド) として追加できます。

暗黙的なコンバーターを定義して、整数 0 ~ 9 の変換、整数への変換を許可し、ToString() をオーバーライドしてタプルの見栄えを良くすることができます。

これは、列挙型よりもはるかに柔軟です。

于 2012-10-04T21:48:55.710 に答える
1

私の意見では、それは悪い習慣です。Hex 表現が必要な場合は、必要なすべての操作を処理するヘルパー クラスを作成するだけです。

この記事が示唆するように、これらのコード スニペットはヘルパーの作成に役立ちます。

// Store integer 182
int decValue = 182;
// Convert integer 182 as a hex in a string variable
string hexValue = decValue.ToString("X");
// Convert the hex string back to the number
int decAgain = int.Parse(hexValue, System.Globalization.NumberStyles.HexNumber);

それが悪い習慣だと私が信じる理由は、それがオブジェクト指向ではないためであり、ハードコードされたすべての値を変換するために列挙型に依存するという問題に遭遇します-これは悪いことです. ハードコーディングを避けることができれば、それは常に正しい方向への一歩です。また、ヘルパー クラスは拡張可能であり、機能を追加するために時間をかけて改善できます。

そうは言っても、私は列挙型の単純さが好きですが、繰り返しますが、それは私の意見ではオブジェクト指向を維持する必要性に取って代わるものではありません。

于 2012-10-12T13:44:44.660 に答える
0

これを行う理由は特にわかりませんが、各列挙値で Description 属性を使用して _ を取り除き、列挙値の 1 つを取得できる何らかの静的関数を作成できます。簡単に Hex(15) -> 'F' のように。

public enum Hex {
    [Description("0")] _0 = 0,
    ...
}
于 2012-10-12T04:22:11.800 に答える
0

ここで実際に何を達成しようとしているのかはわかりませんが、何かを 2 桁の 16 進数に制限しようとしている場合、それをバイトとして宣言しないのはなぜですか? あなたの列挙型ハックは巧妙ですが、実際にはその必要性がわかりません。また、列挙型に対して宣言されていない値を使用することは直感に反するため、説明なしに別のプログラマーに渡すと誤解される可能性があります。

数の基数とリテラル表現に関しては、コンピューティングにおける整数は、本来は基数 10 または基数 16 ではなく、実際には基数 2 (バイナリ) であり、その他の表現は人間の便宜に基づいています。この言語には、10 進数と 16 進数の両方の形式でリテラル数を表す方法が既に含まれています。数を制限することは、タイプを適切に選択する機能です。

代わりに、何かを任意の偶数の 16 進数字に制限しようとしている場合は、おそらく次のように単純にバイト配列を初期化する方が適切です。

    byte[] hexBytes = new byte[3] { 0xA1, 0xB2, 0xC3 };

また、値を列挙型でタプルに入れるのではなく、通常の数値型として保持するか、バイト配列を使用することで、他の方法ではより困難になる操作全体への簡単なアクセスを維持できます。

数値を任意の奇数の 16 進数に制限することに関しては、少なくとも目的の値 + 1 桁を含む型を選択し、実行時に値を制限できます。これの 1 つの可能な実装は次のとおりです。

    public class ThreeNibbleNumber
    {
        private _value;
        public ushort Value
        {
            get
            {
                return _value;
            }
            set
            {
                if (value > 4095)
                {
                    throw new ArgumentException("The number is too large.");
                }
                else
                {
                    _value = value;
                }
            }
        }

        public override string ToString()
        {
            return Value.ToString("x");
        }
    }

別の回答に対するコメントの1つで、CSSカラーを実行するというアイデアを参照しています。それがあなたが望むものなら、次のような解決策が適切だと思われます:

    public struct CssColor
    {
        public CssColor(uint colorValue)
        {
            byte[] colorBytes = BitConverter.GetBytes(colorValue);

            if (BitConverter.IsLittleEndian)
            {
                if (colorBytes[3] > 0)
                {
                    throw new ArgumentException("The value is outside the range for a CSS Color.", "s");
                }

                R = colorBytes[2];
                G = colorBytes[1];
                B = colorBytes[0];
            }
            else
            {
                if (colorBytes[0] > 0)
                {
                    throw new ArgumentException("The value is outside the range for a CSS Color.", "s");
                }

                R = colorBytes[1];
                G = colorBytes[2];
                B = colorBytes[3];
            }
        }

        public byte R;
        public byte G;
        public byte B;

        public override string ToString()
        {
            return string.Format("#{0:x}{1:x}{2:x}", R, G, B).ToUpperInvariant();
        }

        public static CssColor Parse(string s)
        {
            if (s == null)
            {
                throw new ArgumentNullException("s");
            }

            s = s.Trim();
            if (!s.StartsWith("#") || s.Length > 7)
            {
                throw new FormatException("The input is not a valid CSS color string.");
            }

            s = s.Substring(1, s.Length - 1);

            uint color = uint.Parse(s, System.Globalization.NumberStyles.HexNumber);

            return new CssColor(color);
        }
    }
于 2012-10-10T15:56:02.397 に答える