Прочитать на английском

Поделиться через


Func<TResult> Делегат

Определение

Инкапсулирует метод, который не имеет параметров и возвращает значение типа, указанного в параметре TResult.

C#
public delegate TResult Func<out TResult>();
C#
public delegate TResult Func<TResult>();

Параметры типа

TResult

Тип возвращаемого значения метода, инкапсулируемого данным делегатом.

Это ковариантный параметр типа. Это означает, что вы можете использовать любой из указанных типов или любой тип, являющийся более производным. Дополнительные сведения о ковариантности и контрвариантности см. в статье Ковариантность и контрвариантность в универсальных шаблонах.

Возвращаемое значение

TResult

Возвращаемое значение метода, инкапсулируемого данным делегатом.

Примеры

В следующем примере показано, как использовать делегат, который не принимает параметров. Этот код создает универсальный класс с именем LazyValue , который имеет поле типа Func<TResult>. Это поле делегата может хранить ссылку на любую функцию, возвращающую значение типа, соответствующего параметру LazyValue типа объекта. Тип LazyValue также имеет Value свойство, которое выполняет функцию (если она еще не выполнена) и возвращает полученное значение.

В примере создаются два метода и создаются два LazyValue объекта с лямбда-выражениями, которые вызывают эти методы. Лямбда-выражения не принимают параметры, так как они просто должны вызывать метод. Как показано в выходных данных, два метода выполняются только при извлечении значения каждого LazyValue объекта.

C#
using System;

static class Func1
{
   public static void Main()
   {
      // Note that each lambda expression has no parameters.
      LazyValue<int> lazyOne = new LazyValue<int>(() => ExpensiveOne());
      LazyValue<long> lazyTwo = new LazyValue<long>(() => ExpensiveTwo("apple"));

      Console.WriteLine("LazyValue objects have been created.");

      // Get the values of the LazyValue objects.
      Console.WriteLine(lazyOne.Value);
      Console.WriteLine(lazyTwo.Value);
   }

   static int ExpensiveOne()
   {
      Console.WriteLine("\nExpensiveOne() is executing.");
      return 1;
   }

   static long ExpensiveTwo(string input)
   {
      Console.WriteLine("\nExpensiveTwo() is executing.");
      return (long)input.Length;
   }
}

class LazyValue<T> where T : struct
{
   private Nullable<T> val;
   private Func<T> getValue;

   // Constructor.
   public LazyValue(Func<T> func)
   {
      val = null;
      getValue = func;
   }

   public T Value
   {
      get
      {
         if (val == null)
            // Execute the delegate.
            val = getValue();
         return (T)val;
      }
   }
}
/* The example produces the following output:

    LazyValue objects have been created.

    ExpensiveOne() is executing.
    1

    ExpensiveTwo() is executing.
    5
*/

Комментарии

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

Примечание

Чтобы ссылаться на метод без параметров и возвращающих (void``unitв F#) (или в Visual Basic, который объявлен как не как Sub aFunction), используйте Action вместо него делегат.

При использовании делегата Func<TResult> не нужно явно определять делегат, который инкапсулирует метод без параметров. Например, следующий код явно объявляет делегат с именем WriteMethod и назначает ссылку на метод экземпляра OutputTarget.SendToFile его экземпляру.

C#
using System;
using System.IO;

delegate bool WriteMethod();

public class TestDelegate
{
   public static void Main()
   {
      OutputTarget output = new OutputTarget();
      WriteMethod methodCall = output.SendToFile;
      if (methodCall())
         Console.WriteLine("Success!");
      else
         Console.WriteLine("File write operation failed.");
   }
}

public class OutputTarget
{
   public bool SendToFile()
   {
      try
      {
         string fn = Path.GetTempFileName();
         StreamWriter sw = new StreamWriter(fn);
         sw.WriteLine("Hello, World!");
         sw.Close();
         return true;
      }
      catch
      {
         return false;
      }
   }
}

В следующем примере этот код упрощается путем создания экземпляра Func<TResult> делегата вместо явного определения нового делегата и назначения именованного метода ему.

C#
using System;
using System.IO;

public class TestDelegate
{
   public static void Main()
   {
      OutputTarget output = new OutputTarget();
      Func<bool> methodCall = output.SendToFile;
      if (methodCall())
         Console.WriteLine("Success!");
      else
         Console.WriteLine("File write operation failed.");
   }
}

public class OutputTarget
{
   public bool SendToFile()
   {
      try
      {
         string fn = Path.GetTempFileName();
         StreamWriter sw = new StreamWriter(fn);
         sw.WriteLine("Hello, World!");
         sw.Close();
         return true;
      }
      catch
      {
         return false;
      }
   }
}

Делегат можно использовать Func<TResult> с анонимными методами в C#, как показано в следующем примере. (Общие сведения об анонимных методах см. в разделе "Анонимные методы".)

C#
using System;
using System.IO;

public class Anonymous
{
   public static void Main()
   {
      OutputTarget output = new OutputTarget();
      Func<bool> methodCall = delegate() { return output.SendToFile(); };
      if (methodCall())
         Console.WriteLine("Success!");
      else
         Console.WriteLine("File write operation failed.");
   }
}

public class OutputTarget
{
   public bool SendToFile()
   {
      try
      {
         string fn = Path.GetTempFileName();
         StreamWriter sw = new StreamWriter(fn);
         sw.WriteLine("Hello, World!");
         sw.Close();
         return true;
      }
      catch
      {
         return false;
      }
   }
}

Вы также можете назначить лямбда-выражение делегату Func<T,TResult> , как показано в следующем примере. (Общие сведения о лямбда-выражениях см. в разделе лямбда-выражений (VB), лямбда-выражений (C#) и лямбда-выражений (F#).)

C#
using System;
using System.IO;

public class Anonymous
{
   public static void Main()
   {
      OutputTarget output = new OutputTarget();
      Func<bool> methodCall = () => output.SendToFile();
      if (methodCall())
         Console.WriteLine("Success!");
      else
         Console.WriteLine("File write operation failed.");
   }
}

public class OutputTarget
{
   public bool SendToFile()
   {
      try
      {
         string fn = Path.GetTempFileName();
         StreamWriter sw = new StreamWriter(fn);
         sw.WriteLine("Hello, World!");
         sw.Close();
         return true;
      }
      catch
      {
         return false;
      }
   }
}

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

Если у вас есть ресурсоемкие вычисления, которые необходимо выполнить только в том случае, если результат действительно необходим, можно назначить ресурсоемкой функции делегату Func<TResult> . Затем выполнение функции может быть отложено до тех пор, пока свойство, которое обращается к значению, будет использоваться в выражении. В следующем разделе показано, как это сделать.

Методы расширения

GetMethodInfo(Delegate)

Получает объект, представляющий метод, представленный указанным делегатом.

Применяется к

Продукт Версии
.NET Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7
.NET Framework 3.5, 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8
.NET Standard 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 2.0, 2.1
UWP 10.0

См. также раздел