在 C# 枚举中使用哨兵值(编译时枚举的大小)?
在处理嵌入式 API(主要是通信协议)时,我在 C 中经常使用的快捷方式允许我编辑枚举数组,并在之后正确调整其他所有内容的大小:
typedef enum {
errortype1,
errortype2,
...
errortypeN,
ERROR_TYPE_MAX
} ErrorTypeList;
int errorcounts[ERROR_TYPE_MAX]; // Create array to hold a counter for each error type
只要我在 ERROR_TYPE_MAX 之前添加新的错误类型,那么我就可以使用该值其他地方都可以给我枚举的大小。
然而,在 C# 中,这不能按原样工作:
enum ErrorTypeList {
errortype1,
errortype2,
...
errortypeN,
ERROR_TYPE_MAX
};
int errorcounts[ErrorTypeList.ERROR_TYPE_MAX]; // Create array to hold a counter for each error type
此用法会出现错误无法在变量声明中指定数组大小
,建议使用new
。
在运行时定义数组(通过 new )是我唯一的选择,还是有办法在不使用 new 的情况下完成此操作,因为编译后枚举的大小不会改变?
这种类型的枚举大小调整模式是否有更适合 C# 的替代方案?
A shortcut I often use in C when dealing with embedded APIs (communications protocols, primarily) allows me to edit an enum array and have everything else sized correctly after that:
typedef enum {
errortype1,
errortype2,
...
errortypeN,
ERROR_TYPE_MAX
} ErrorTypeList;
int errorcounts[ERROR_TYPE_MAX]; // Create array to hold a counter for each error type
As long as I add new error types before ERROR_TYPE_MAX then I can use that value everywhere else to give me the size of the enum.
In C#, however, this doesn't work as-is:
enum ErrorTypeList {
errortype1,
errortype2,
...
errortypeN,
ERROR_TYPE_MAX
};
int errorcounts[ErrorTypeList.ERROR_TYPE_MAX]; // Create array to hold a counter for each error type
This usage presents the error Array size cannot be specified in a variable declaration
which suggests using new
.
Is defining the array at runtime (via new
) my only option, or is there a way to accomplish this without a new, since the size of the enum isn't going to change after compilation?
Is there an alternative to this type of enum sizing pattern that better fits into c#?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
如果您想要枚举的大小,您可以这样做:
但这不会给您您想要的,因为
sizeof
返回以八位字节为单位的对象的大小( 4 在本例中,由于枚举,默认情况下包装 Int32)。要获取枚举中的值的数量,请执行以下操作:
如果您打算使用枚举的值来索引数组,则应该注意这使得[无根据]假设枚举的值从 0 开始并以 1 递增:对枚举定义的后续更改违反了该假设将会破坏事物。
此外,如果枚举应用了
[Flags]
属性,则枚举的域可能比定义的离散值的数量大得多。您最好使用字典,因此:
现在您的代码更加灵活:您不关心枚举的内部结构如何排列。
您甚至可以使用预期的键集预先填充字典(如果传递的值与预期不同,则抛出异常)。
编辑注意:
您也可以执行类似的操作:
CreateArrayBasedOnFoo()
方法将返回一个大小适合枚举的数组,其下限为枚举的最小值。例如,如果枚举有 3 个离散值:3、5 和 7,则传回的数组长度将为 5 个元素,下限为 3。If you want the size of an enum, you can do this:
But that won't give you what you want, since
sizeof
returns the size of the object in octets (4 in this case, since an enum, by default wraps an Int32).To get the number of values in the enum, do something like this:
If you're planning on using the value of the enum to index into the array, you should note that this makes the [unwarranted] assumption that the enum's values start at 0 and increment by 1: a subsequent change to the enum's definition that violates the assumption will break things.
Further, if the enum has the
[Flags]
attribute applied to it, then the domain of the enum is potentially [much] larger than the number of discrete values defined.You would be better off to use a dictionary, thus:
Now your code is much more flexible: you don't care about how the internals of the enum are arranged.
You might even pre-populate the dictionary with the expected set of keys (and throw an exception if handed a value other than the expected).
Edited To Note:
You could do something like this as well:
The
CreateArrayBasedOnFoo<T>()
method will hand back an array sized to fit the enum and whose lower bound is the smallest value of the enum. For instance, if you enum has 3 discrete values: 3, 5 and 7, the array handed back will be 5 elements in length and will have a lower bound of 3.您必须使用
new
。变量/字段声明不指定数组的大小,这仅在构造数组实例时完成。
您最多可以指定数组有多少个维度,但不能指定每个维度的大小。
You will have to use
new
.A variable/field declaration does not specify the size of the array, that's only accomplished when you construct the array instance.
At most you can specify how many dimensions the array will have, but not the size of each dimension.
要回答问题的第二部分,您可以使用
Enum
类获取enum
中的条目数,如下所示:请注意,计数器中的技巧仅当也可以工作。当然,您需要在开始时将计数初始化为零,以避免运行时出现“元素不存在”异常。
enum
值连续时,数组才有效。这比Dictionary
更脆弱,即使您决定为枚举常量分配非连续值或负值,DictionaryTo answer the second part of your question, you can get the number of entries in your
enum
by using theEnum
class, like this:Note that the trick with counters in an array works only when the
enum
values are consecutive. This is somewhat more fragile than aDictionary<ErrorTypeList,int>
, which would work even if you decide to assign your enumeration constants non-consecutive or negative values. Of course you would need to initialize the counts to zero at the beginning to avoid the "element is not there" exception at runtime.您只能在
不安全结构
中定义固定长度数组。否则,C# 仅支持在运行时使用new
创建数组。由于数组是引用类型并存储在堆上,因此这不会产生任何性能差异。
You can only define fixed length arrays in an
unsafe struct
. Otherwise C# only supports creating arrays at run-time usingnew
.Since arrays are a reference type and stored on the heap, this should not make any performance difference.
由于枚举条目初始值设定项,我认为使用枚举条目的数量对 C# 中的枚举值执行边界检查是不安全的做法。
有足够的验证方法,例如 Enum.IsDefined() 和 Enum.ToObject(),可让您更安全地验证数值并将其转换为特定类型的枚举条目。
请参阅有关 Enum 类的 MSDN 参考:
http://msdn.microsoft .com/en-us/library/system.enum.aspx
编辑以解决澄清的问题陈述...
我认为映射枚举值和整数计数器的字典会更好地满足您的需求。如果有人将初始值设定项粘贴到您的一个或多个枚举条目上,它仍然会起作用。
如果您确实想预先初始化它:
否则,我可能只会在发生错误情况时添加条目
Because of enum entry initializers, I think it is an unsafe practice to use the number of enum entries perform bounds checking on an enum value in C#.
There are ample validation methods such as Enum.IsDefined() and Enum.ToObject() to allow you to more safely validate and convert numeric values to type specific enum entries.
Please see the MSDN reference on the Enum class:
http://msdn.microsoft.com/en-us/library/system.enum.aspx
Edited to address clarified problem statement...
I think a dictionary mapping enum values and integer counters would better serve your needs. It will still work if somebody sticks an initializer on one or more of your enum entries.
and if you really want to pre-initialize it:
otherwise, I would probably only add entries as the error condition occurs