В устаревшей кодовой базе по многим техническим причинам мы заменяем параметры, которые ранее имели тип базового класса, на тип интерфейса.Например:
public interface IDomainObject { int Id { get; } }
public abstract class BaseDomainObject : IDomainObject
{
public int Id { get; protected set; }
public override bool Equals(object obj)
{
var domainObj = obj as BaseDomainObject;
return domainObj != null && Id.Equals(domainObj.Id);
}
public static bool operator ==(BaseDomainObject x, BaseDomainObject y)
{
return !ReferenceEquals(x, null) && !ReferenceEquals(y, null) && x.Equals(y);
}
public static bool operator !=(BaseDomainObject x, BaseDomainObject y)
{
return !(x == y);
}
}
public class MyDomainObject : BaseDomainObject
{
public MyDomainObject(int id) { Id = id; }
...
}
Таким образом, везде в коде, где у нас ранее была бы переменная типа BaseDomainObject , теперь у нас есть один из типов IDomainObject .Однако у нас возникают проблемы с оператором '==' - он не работает с интерфейсами.Для всех типов интерфейса оператор '==' просто возвращается к ReferenceEquals () .
Следующий код демонстрирует проблему:
// Old style
BaseDomainObject baseobj1A = new MyDomainObject(1);
BaseDomainObject baseobj1B = new MyDomainObject(1);
BaseDomainObject baseobj2 = new MyDomainObject(2);
Assert.IsTrue(baseobj1A != baseobj2);
Assert.IsTrue(baseobj1A == baseobj1B); // Succeeds
// New style
IDomainObject iobj1A = new MyDomainObject(1);
IDomainObject iobj1B = new MyDomainObject(1);
IDomainObject iobj2 = new MyDomainObject(2);
Assert.IsTrue(iobj1A != iobj2);
Assert.IsTrue(iobj1A == iobj1B); // Fails
Возвращение к использованию базового класса не вариант - наш интерфейс является общим ко-вариантом (аналогично IDomainObject) что необходимо для полиморфного поведения, которое нам нужно.В идеале мы просто заменили бы все '==' на .Equals () .Однако наша кодовая база огромна, и найти все операторы '==', о которых мы заботимся, было бы огромной задачей.
Одна мысль заключалась в том, что мы могли бы написать правило FxCop, которое будет отмечать все вхождения переменной определенного типа интерфейса (т. Е. IDomainObject ), используемой при сравнении '=='.Но это не сработало - FxCop не поддерживает это.Другая мысль заключалась в том, чтобы написать наш собственный инструмент для анализа кода, который просто проверяет этот случай, но это отнимает много времени.
Итак, вопрос в том, существует ли уже какой-то инструмент анализа кода, который мы могли бы использовать, чтобы найти эти вхождения "=="?