Использование предикатов делегата

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

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

Зачем кому-то использовать предикаты, если они не принимают других параметров, кроме 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

РЕДАКТИРОВАТЬ: использование Lambda для того же, ниже.

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. В статье приводятся хорошие примеры, но, похоже, я не отвечаю на мой вопрос.


person LastTribunal    schedule 28.01.2015    source источник
comment
лямбда - это просто частный случай захвата (доступный с использованием анонимных методов, начиная с .NET 2.0), который, в свою очередь, является просто частным случаем метода, имеющего возможность доступа к полям своего собственного класса, доступного с момента появления .NET.   -  person Ben Voigt    schedule 28.01.2015


Ответы (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);

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

person Peter Duniho    schedule 29.01.2015