[英]Is the use of implicit enum fields to represent numeric values a bad practice?
使用隱式枚舉字段來表示數值是一種必然的壞習慣嗎?
這是一個用例:我想要一種簡單的方法來表示十六進制數字,並且因為C#枚舉基於整數,所以它們看起來像是自然匹配。 我不喜歡這里的char
或string
,因為我必須明確驗證它們的值。 枚舉的問題是數字[0-9]
不是有效的字段標識符(有充分的理由)。 在我看來,我不需要聲明數字0-9
,因為它們是隱式存在的。
所以,我的十六進制數字枚舉看起來像:
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
}
問題是上面的例子會給我“F_1”而不是“F1”。 顯然,這很容易解決。 我想知道我沒有考慮的隱式方法是否存在其他問題。
這是一種不好的做法,因為這是一個聰明的技巧,這對於閱讀代碼的人來說是令人驚訝的。 令我感到驚訝的是它確實有效,它讓我說wtf。 記住唯一有效的代碼質量測量:
聰明的技巧不屬於那些意圖由他人閱讀和維護的代碼。 如果要將數字輸出為十六進制,請使用普通的String.Format("{0:X}", value)
將其轉換為十六進制字符串
這是一種處理十六進制的根本方法。 Hex是人機界面細節。 它總是一個字符串 ,一個數字的表示。 類似“1234”是值1234的表示。當以十六進制表示時恰好為“4D2”,但程序中的數字仍然是1234.程序應該只關注數字,而不是表示。
只有當您向人眼顯示數字時才會將數字轉換為十六進制。 簡單地使用ToString(“X”)。 並使用NumberStyles.HexNumber使用TryParse()從人類輸入中解析回來。 輸入和輸出,在任何其他方面都不應該處理十六進制。
我會為HexDigit
定義一個struct
。 您可以將HexDigit
'添加到'F'作為靜態常量(或靜態只讀字段)。
您可以定義隱式轉換器以允許轉換整數0-9,轉換為整數,並且您可以重寫ToString()以使您的元組看起來不錯。
這比枚舉更靈活。
在我看來,這是一個不好的做法。 如果需要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);
我認為這是不好的做法的原因是因為它不是面向對象的,並且它遇到了依賴枚舉來翻譯所有硬編碼值的問題 - 這很糟糕。 如果你可以避免任何硬編碼,那么它始終是朝着正確方向邁出的一步。 此外,輔助類是可擴展的,並且可以隨着時間的推移進行改進以獲得其他功能。
話雖這么說,我喜歡簡單的枚舉,但是,再次,這並不能取代在我看來保持OO的必要性。
我不確定你在這里想要實現什么,但是如果你想限制兩個十六進制數字,你為什么不把它聲明為一個字節呢? 雖然你的枚舉很聰明,但我實際上並沒有看到它的必要性。 如果在沒有解釋的情況下傳遞給另一個程序員,它也可能是誤導,因為你對你的枚舉使用未聲明的值是違反直覺的。
關於數字基數和文字表示,計算中的整數本身不是base-10或base-16,它實際上是base-2(二進制),並且任何其他表示都是人類的便利。 該語言已經包含以十進制和十六進制格式表示文字數字的方法。 限制數量是適當選擇類型的函數。
如果您試圖將某些內容限制為任意數量的十六進制數字,那么簡單地初始化像這樣的字節數組會更合適:
byte[] hexBytes = new byte[3] { 0xA1, 0xB2, 0xC3 };
此外,通過將您的值保持為常規數字類型或使用字節數組而不是將其放入帶枚舉的元組,您可以保留對一系列操作的簡單訪問,否則這些操作將變得更加困難。
關於將數字限制為任意奇數量的十六進制數字,您可以選擇至少包含所需值+ 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");
}
}
在你對另一個答案的評論中,你提到了做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);
}
}
我不是特別明白你為什么要這樣做,但你可以在每個枚舉值上使用Description屬性來擺脫_並創建某種靜態函數,它允許你得到你的一個枚舉值很像Hex(15) - >'F'。
public enum Hex {
[Description("0")] _0 = 0,
...
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.