为什么同一属性的两个不同实例在这里相等?

时间:2019-06-12 16:51:53

标签: c# attributes equality

我有两个类,它们的属性相同但值不同。当我将它们转储到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();

我在这里缺少什么?如何正确比较它们?

1 个答案:

答案 0 :(得分:1)

A1属性类声明了具有私有编译器生成的后备字段的自动属性。

现在,当Attribute.Equals方法在A2上进行访问以访问其所有实例字段时( Attribute.Equals 不会在属性上进行反映),它将不会“看到” A1中声明的私有后备字段,因为不能通过派生类型访问基本类型的私有成员。 (另请参见此处:Are private members inherited in C#?

因此,当尝试使用 Attribute.Equals 实现比较A2类型的两个实例(其本身没有声明任何字段)时,结果将为true (因为两个属性实例的类型是相同的A2类型,并且这些实例不包含任何可以通过A2类型访问的字段)。

可能的解决方案(取决于当前的实际应用场景)可能(其中包括)使用公共字段代替属性类中的公共属性,或者覆盖基本属性类中的Equals()方法({ {1}}),它反映并比较类型,两个属性实例的所有公共字段