Почему два разных экземпляра одного и того же атрибута здесь равны? - PullRequest
2 голосов
/ 12 июня 2019

У меня есть два класса, которые имеют один и тот же атрибут, но разные значения.Когда я сбрасываю их в 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 Ответ

1 голос
/ 12 июня 2019

Класс атрибута A1 объявляет авто-свойство с частным вспомогательным полем, созданным компилятором.

Теперь, когда метод Attribute.Equals отображает более A2 для доступа ко всем его полям экземпляра ( Attribute.Equals не отражает свойства), он "не увидит" msgstr "закрытое поле поддержки, объявленное в A1, так как закрытые члены базового типа не доступны через производный тип. (См. Также здесь: Частные члены наследуются в C #? )

Таким образом, при попытке сравнить два экземпляра типа A2 - который сам по себе не объявляет никаких полей - с использованием реализации Attribute.Equals , результатом будет true (поскольку тип два экземпляра атрибута имеют одинаковый тип A2, и экземпляры не содержат полей, которые были бы доступны через тип A2).

Возможные решения (в зависимости от действующего сценария приложения) могут включать (среди прочего) использование открытых полей вместо открытых свойств в классах атрибутов или, возможно, переопределение метода Equals() в базовом классе атрибутов (A1 ), который отражает и сравнивает тип, все открытые поля и дополнительно все открытые свойства двух экземпляров атрибута.

...