MSDN.WhiteKnight - Stack Overflow answers
Ответ на "Сравнение Func<T, TResult> на равенство. C#"
Answer 1171446
Сравнение делегатов работает следующим образом: https://docs.microsoft.com/en-us/dotnet/api/system.delegate.equals?view=netcore-3.1
If the two methods being compared are both static and are the same method on the same class, the methods are considered equal and the targets are also considered equal.
If the two methods being compared are instance methods and are the same method on the same object, the methods are considered equal and the targets are also considered equal.
Otherwise, the methods are not considered to be equal and the targets are also not considered to be equal.
Увы, два разных лямбда выражения вида
s => s.Name
, даже если в коде они идентичны, представляются в бинарнике разными анонимными методами, так что сравнение делегатов работать не будет.Но если методы делают одно и то же, должен же быть способ выяснить это, иными словами, сравнить методы "по значению"? Да, такой способ есть. Так как лямбда-метод - это одиночное выражение, ни блоков обработки исключений, ни локальных переменных в нем быть не может, равенство таких методов, по сути, сводится к побайтовому равенству их IL-кода. Это приводит нас к такому способу сравнения:
using System; using System.Collections.Generic; using System.Text; using System.Linq; using System.Reflection; public class Person { public string Name; public string Location; } class Program { static bool AreMethodsEqual(MethodBase left, MethodBase right) { MethodBody m1 = left.GetMethodBody(); MethodBody m2 = right.GetMethodBody(); byte[] il1 = m1.GetILAsByteArray(); byte[] il2 = m2.GetILAsByteArray(); return il1.SequenceEqual(il2); } static void Main(string[] args) { Func<Person, string> func = s => s.Name; Func<Person, string> predicate = x => x.Name; Console.WriteLine("Результат сравнения делегатов: "+func.Equals(predicate)); Console.WriteLine("Результат сравнения методов: "+AreMethodsEqual(func.Method, predicate.Method)); Console.ReadKey(); } }
Но этот способ работает только для предикатов, полученных из лямбда-выражений, заданных на этапе разработки. Если оно генерируется динамически на основе LINQ Expression, AreMethodsEqual не сработает, так как GetMethodBody выдаст исключение.
Content is retrieved from StackExchange API.
Auto-generated by ruso-archive tools.