2015-01-28 2 views
-1

В приведенном ниже примере показано значение predicate для оценки состояния с жестко запрограммированным значением 100000. Невозможно добавить дополнительные параметры в метод FindPoints, поскольку это нарушит предикатное ограничение параметра.Достоинство делегатов Полезность

Это приводит к вопросу использования предикатов. Очевидно, Лямбда решает эту проблему ... но тем не менее, может кто-нибудь объяснить полезность предикатов в реальных сценариях жизни, учитывая это, казалось бы, странное ограничение.

Почему кто-либо использует предикаты, если они не принимают параметры, отличные от T?

using System; 
using System.Drawing; 

public class Example 
{ 
    public static void Main() 
    { 
     // Create an array of Point structures. 
     Point[] points = { new Point(100, 200), 
         new Point(150, 250), new Point(250, 375), 
         new Point(275, 395), new Point(295, 450) }; 

     // Define the Predicate<T> delegate. 
     Predicate<Point> predicate = FindPoints; 

     // Find the first Point structure for which X times Y 
     // is greater than 100000. 
     Point first = Array.Find(points, predicate); 

     // Display the first structure found. 
     Console.WriteLine("Found: X = {0}, Y = {1}", first.X, first.Y); 
    } 

    private static bool FindPoints(Point obj) 
    { 
     return obj.X * obj.Y > 100000; 
    } 
} 
// The example displays the following output: 
//  Found: X = 275, Y = 395 

EDIT: Использование лямбда для того, чтобы сделать то же самое, ниже.

using System; 
using System.Drawing; 

public class Example 
{ 
    public static void Main() 
    { 
     // Create an array of Point structures. 
     Point[] points = { new Point(100, 200), 
         new Point(150, 250), new Point(250, 375), 
         new Point(275, 395), new Point(295, 450) }; 

     // Find the first Point structure for which X times Y 
     // is greater than 100000. 
     Point first = Array.Find(points, x => x.X * x.Y > 100000); 

     // Display the first structure found. 
     Console.WriteLine("Found: X = {0}, Y = {1}", first.X, first.Y); 
    } 
} 
// The example displays the following output: 
//  Found: X = 275, Y = 395 

Это MSDN. Статья дает хорошие примеры, но, похоже, не затрагивает мой вопрос.

+0

lambda - это особый случай захвата (доступный с использованием анонимных методов с .NET 2.0), который, в свою очередь, является лишь частным случаем метода, позволяющего получать доступ к полям своего собственного класса, доступным с момента внедрения .NET. –

ответ

1

Даже если вы объявляете свой предикат, используя выражение лямбда, предоставляя анонимный метод вместо именованного, лямбда все еще принимает только определенный тип. Просто компилятор запрашивает требуемый тип (но обратите внимание, что C# фактически допускает изменение синтаксиса лямбда, где вы явно указываете тип).

Таким образом, оба подхода одинаково полезны; если вы понимаете, почему один из них полезен (например, синтаксис лямбда), тогда вы понимаете, почему полезен другой.

И они оба полезны, поскольку, передавая экземпляр делегированного предиката, вы разрешаете настраивать поведение метода, который вы вызываете. Например. в этом случае вы используете метод Array.Find(). Использование экземпляра делегированного предиката, независимо от того, хранится ли оно сначала в локальной переменной или просто передается напрямую, и объявляется ли с использованием именованного метода или анонимного, позволяет методу Array.Find() реализовать всю скучную повторяющуюся работу по итерации через массив, позволяя абонентам предоставлять интересную, зависящую от сценария логику.

Чтобы быть ясным, ваши два примера действительно в основном идентичны, тем более, что вы имеете дело со статическим методом для предиката. Есть незначительные различия в объявлениях, но как только оптимизирующий компилятор JIT выполняется с кодом, то, что выполняется во время выполнения, практически одинаково. Даже IL, скомпилированный из вашей программы на C#, будет структурно одинаковым, хотя будут некоторые различия в именах. Вы можете проверить это самостоятельно, сравнив скомпилированные версии, например. с помощью инструмента ildasm.exe или что-то вроде декомпилятора dotPeek.

Я также укажу, что вы указали два примера – использование локальной переменной и именованного метода и использование анонимного метода без локальной переменной –, но есть как минимум два других примера, которые также аналогичны идентичны:

локальная переменная с анонимным методом:

Predicate<Point> predicate = x => x.X * x.Y > 100000; 

    Point first = Array.Find(points, predicate); 

имени метода без локальной переменной:

Point first = Array.Find(points, FindPoints); 

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

Смежные вопросы