Как выражения Linq определяют равенство?

Я рассматриваю возможность использования выражения Linq в качестве ключа в словаре. Тем не менее, я обеспокоен тем, что получаю странные результаты, потому что не знаю, как равенство определяется выражениями Linq.

Является ли класс, полученный из выражения, сравнивать значение равенства или ссылочного равенства? Или, другими словами,

        Expression<Func<object>> first = () => new object(); 
        Expression<Func<object>> second = ()=>new object();
        bool AreTheyEqual = first == second;

Ответ 1

В вашем тесте сравниваются выражения. Выражения сами по себе предлагают только ссылочное равенство; ваш тест, вероятно, будет показывать "ложь". Для щеки для семантического равенства вам нужно будет сделать много работы, например:

x => 123

и

y => 123

Эквивалент? В качестве грубого теста вы можете сравнить ToString(), но это будет исключительно хрупким.

Ответ 2

Сравнение любых двух объектов, которые не являются типами значений (включая выражение) с == сравнивает ссылки на объекты, поэтому они не будут равны. Однако, как заметил комментатор, словарь будет использовать Equals и GetHashCode для определения равенства, которое по-прежнему будет по умолчанию определять, что они не равны.

Возможно, вы могли бы создать класс, который наследует System.Linq.Expression и переопределяет GetHashCode и Equals, чтобы использовать результат каким-то образом, и использовать это как ключ для вашего словаря.

Ответ 3

Как отмечали другие, оператор Expression == использует стандартную проверку ссылочного равенства - "Они оба ссылаются на одно и то же место в куче?". Это означает, что код, подобный вашему примеру, скорее всего вернет false, так как ваши литералы выражения будут созданы как разные экземпляры Expression, независимо от семантического равенства. Подобные расстройства связаны с использованием lambdas в качестве обработчиков событий:

MyEvent += (s, a) => DoSomething();
...
MyEvent -= (s, a) => DoSomething(); //<-- will NOT remove the added handler

Проверка на семантическое равенство сложна. В этом конкретном случае вы можете посетить все узлы дерева выражений и сравнить все строки, типы значений и ссылки на методы, чтобы определить, что они делают то же самое. Однако при проверке два lambdas в следующем примере семантически эквивалентны, но вам трудно написать метод, чтобы доказать это:

   public void MyMethod() {...}
   public void AnotherMethod { MyMethod(); };

   ...

   Action one = () => MyMethod();
   Action two = () => AnotherMethod();

   var equal = one == two; // false