如何从类型变量获取枚举默认值?兼容无0值枚举场景
我现在需要遍历一个设计时未知对象的
PropertyInfo集合来执行处理逻辑,核心需求是判断每个属性的值是否和默认值不同。目前的代码大致如下:foreach(var p in propertyInfos) { if (something) { ... } else if (p.PropertyType.IsEnum) { object oDefault = GetDefaultValueOfThisPropertyByWhateverMethod(); if (oDefault == null) oDefault = default(p.PropertyType); // 这里代码不合法 var vValue = p.GetValue(myObject); if (!oDefault.Equals(vValue)) // 当枚举值不是默认值时执行特定逻辑 } }现在遇到的问题是:如果枚举类型不包含值为0的项,这种情况下该怎么正确实现判断逻辑?
嘿,这个场景我之前踩过坑!首先得明确一个关键规则:不管你有没有在枚举定义里写值为0的项,CLR给枚举类型的默认值永远是0——哪怕这个值没有对应的枚举名称,它依然是合法的枚举实例(调用ToString()会直接返回"0"而已)。
另外你代码里default(p.PropertyType)的写法在C# 7.0之前是不支持的,得换个方式生成默认值。下面给你两种靠谱的实现方式:
方式一:直接用CLR默认值(最通用)
如果你的需求就是判断属性值是否偏离CLR的默认值,直接这么写就行:
foreach(var p in propertyInfos) { if (something) { ... } else if (p.PropertyType.IsEnum) { // 生成枚举的CLR默认值:0,不管枚举有没有定义对应的项 object enumDefault = Enum.ToObject(p.PropertyType, 0); var currentValue = p.GetValue(myObject); // 比较值是否不同 if (!Equals(enumDefault, currentValue)) { // 当枚举值不是默认值时,执行你的专属逻辑 } } }
这里用Enum.ToObject把0转换成目标枚举类型的实例,这是CLR认可的标准默认值,不管枚举有没有定义0对应的项都能正常工作。
方式二:兼容自定义默认值逻辑
如果你的GetDefaultValueOfThisPropertyByWhateverMethod()是用来获取自定义标记的默认值(比如通过DefaultValueAttribute指定的枚举项),那可以先优先用这个方法的返回值,再兜底到CLR默认的0:
foreach(var p in propertyInfos) { if (something) { ... } else if (p.PropertyType.IsEnum) { object customDefault = GetDefaultValueOfThisPropertyByWhateverMethod(); // 如果自定义默认值不存在,就用CLR的0默认值 object enumDefault = customDefault ?? Enum.ToObject(p.PropertyType, 0); var currentValue = p.GetValue(myObject); // 额外处理可空枚举的情况:如果当前值是null,肯定不等于默认值 if (currentValue == null || !enumDefault.Equals(currentValue)) { // 执行你的枚举特定逻辑 } } }
补充个小细节:如果是可空枚举(比如Nullable<MyEnum>),currentValue可能为null,这种情况直接判定为偏离默认值就好。
最后再啰嗦一句:千万别依赖枚举定义里有没有0值,CLR对值类型(包括枚举)的默认值规则是固定的——内存清零后的状态,对应枚举就是0。
内容的提问来源于stack exchange,提问作者Sierramike

