C#反射获取类中值类型属性值时出现不等问题的原因
问题:反射获取值类型属性后用
!=判定为不同的原因? 我编写了以下代码片段重现遇到的场景,但无法解释观察到的行为:
public class X { public string XS { get; set; } public int XN { get; set; } public MyEnum Enum { get; set; } } void testValueTypesReflectionComparison() { var x1 = new X { XN = 1, XS = "argh", Enum = MyEnum.Component }; var x2 = new X { XN = 1, XS = "argh", Enum = MyEnum.Component }; var xTypeProperties = x1.GetType().GetProperties(); foreach(var property in xTypeProperties) { var x1PropertyValue = property.GetValue(x1, null); var x2PropertyValue = property.GetValue(x2, null); if (x1PropertyValue != x2PropertyValue) { Console.WriteLine($"different values on property: [{property.Name}]: x1: [{x1PropertyValue}] x2: [{x2PropertyValue}]"); } } }
输出:
我在PropertyInfo.GetValue文档中未找到关于获取值类型的特殊说明。为何反射获取的XN和Enum属性值在x1和x2实例中被判定为不同?
解答
核心原因:装箱引发的引用比较
PropertyInfo.GetValue的返回类型是object,当获取int、枚举这类值类型的属性时,值会被装箱——也就是包装成一个独立的object实例。
用!=比较两个object时,默认执行的是引用地址比较,而非值比较。即使两个装箱对象的值完全相同,它们也是内存中两个独立的对象,引用地址不同,因此!=会返回true,被判定为“不同”。字符串为何不受影响?
字符串属于引用类型,但CLR会对字符串字面量做驻留优化:相同内容的字符串字面量会指向内存中的同一个实例。因此用!=做引用比较时,相同内容的字符串会返回false,不会被判定为不同。正确的比较方式
要准确比较属性值,应使用object.Equals(x1PropertyValue, x2PropertyValue)——它会先检查引用是否一致,若不一致则调用对应类型的Equals方法做值比较。修改后的判断代码如下:
if (!object.Equals(x1PropertyValue, x2PropertyValue)) { Console.WriteLine($"different values on property: [{property.Name}]: x1: [{x1PropertyValue}] x2: [{x2PropertyValue}]"); }
内容的提问来源于stack exchange,提问作者Veverke
相关产品推荐
相关产品推荐

