Как выражения Linq определяют равенство? - PullRequest
11 голосов
/ 17 февраля 2011

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

Сравнивает ли класс, полученный из Expression, равенство значений или ссылочное равенство?Или, другими словами,

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

Ответы [ 3 ]

11 голосов
/ 17 февраля 2011

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

x => 123

И

y => 123

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

0 голосов
/ 17 февраля 2011

Как уже отмечали другие, оператор Expression == использует стандартную проверку «равенство ссылок» - «Являются ли они обе ссылкой на одно и то же место в куче?».Это означает, что код, подобный вашему примеру, скорее всего, вернет false, поскольку литералы вашего выражения будут создаваться как разные экземпляры Expression независимо от какого-либо семантического равенства.Существуют похожие проблемы с использованием лямбда-выражений в качестве обработчиков событий:

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

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

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

   ...

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

   var equal = one == two; // false
0 голосов
/ 17 февраля 2011

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

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

...