为什么同一属性的两个不同实例在这里相等?
Why are two different instances of the same attribute equal here?
我有两个 类 装饰有相同的属性但不同的值。当我将它们转储到 LINQPad 中时,我可以看到它们是不同的,但是当我执行 x.Equals(y)
时,它会产生 true
,即使 Equals
的实现实际上比较了 属性 值。
这段代码重现了这个问题:
void Main()
{
var a1 = typeof(T1).GetCustomAttribute<A2>().Dump();
var a2 = typeof(T3).GetCustomAttribute<A2>().Dump();
a1.Equals(a2).Dump();
}
[A1(V = "I1")]
interface I1
{
[A1(V = "I1.P1")]
string P1 { get; set; }
}
[A2(V = "T1")] // <-- typeof(T1).GetCustomAttribute<A2>()
class T1 : I1
{
[A1(V = "T1.P1")]
public virtual string P1 { get; set; }
}
class T2 : T1 { }
[A1(V = "T3"), A2(V = "T3")] // <-- typeof(T3).GetCustomAttribute<A2>()
class T3 : T2
{
[A1(V = "T3.P1")]
public override string P1 { get; set; }
}
class A1 : Attribute { public string V { get; set; } }
class A2 : A1 { }
结果如下:
UserQuery+A2
TypeId = typeof(A2)
V = T1
UserQuery+A2
TypeId = typeof(A2)
V = T3
True // <-- a1.Equals(a2).Dump();
我在这里遗漏了什么以及如何正确比较它们?
A1
属性 class 声明了一个带有私有 compiler-generated 支持字段的 auto-property。
现在,当 Attribute.Equals
method reflects over A2
to access all its instance fields (Attribute.Equals does not reflect over properties), it will not "see" the private backing field declared in A1
, since private members of a base type are not accessible through a derived type. (See also here: Are private members inherited in C#?)
因此,当尝试使用 Attribute.Equals 实现比较类型 A2
的两个实例时(它本身不声明任何字段),结果将是 true
(因为两个属性实例的类型是相同的类型 A2
,并且这些实例不具有可通过 A2
类型访问的任何字段)。
可能的解决方案(取决于手头的实际应用场景)可能是(除其他事项外)使用 public 字段而不是属性 classes 中的 public 属性,或者也许覆盖反映和比较类型的基本属性 class (A1
) 中的 Equals()
方法,此外,所有 public 字段 和 两个属性实例的所有 public 个属性。
我有两个 类 装饰有相同的属性但不同的值。当我将它们转储到 LINQPad 中时,我可以看到它们是不同的,但是当我执行 x.Equals(y)
时,它会产生 true
,即使 Equals
的实现实际上比较了 属性 值。
这段代码重现了这个问题:
void Main()
{
var a1 = typeof(T1).GetCustomAttribute<A2>().Dump();
var a2 = typeof(T3).GetCustomAttribute<A2>().Dump();
a1.Equals(a2).Dump();
}
[A1(V = "I1")]
interface I1
{
[A1(V = "I1.P1")]
string P1 { get; set; }
}
[A2(V = "T1")] // <-- typeof(T1).GetCustomAttribute<A2>()
class T1 : I1
{
[A1(V = "T1.P1")]
public virtual string P1 { get; set; }
}
class T2 : T1 { }
[A1(V = "T3"), A2(V = "T3")] // <-- typeof(T3).GetCustomAttribute<A2>()
class T3 : T2
{
[A1(V = "T3.P1")]
public override string P1 { get; set; }
}
class A1 : Attribute { public string V { get; set; } }
class A2 : A1 { }
结果如下:
UserQuery+A2 TypeId = typeof(A2) V = T1 UserQuery+A2 TypeId = typeof(A2) V = T3 True // <-- a1.Equals(a2).Dump();
我在这里遗漏了什么以及如何正确比较它们?
A1
属性 class 声明了一个带有私有 compiler-generated 支持字段的 auto-property。
现在,当 Attribute.Equals
method reflects over A2
to access all its instance fields (Attribute.Equals does not reflect over properties), it will not "see" the private backing field declared in A1
, since private members of a base type are not accessible through a derived type. (See also here: Are private members inherited in C#?)
因此,当尝试使用 Attribute.Equals 实现比较类型 A2
的两个实例时(它本身不声明任何字段),结果将是 true
(因为两个属性实例的类型是相同的类型 A2
,并且这些实例不具有可通过 A2
类型访问的任何字段)。
可能的解决方案(取决于手头的实际应用场景)可能是(除其他事项外)使用 public 字段而不是属性 classes 中的 public 属性,或者也许覆盖反映和比较类型的基本属性 class (A1
) 中的 Equals()
方法,此外,所有 public 字段 和 两个属性实例的所有 public 个属性。