Func<TResult> 委托

定义

封装一个方法,该方法不具有参数,且返回由 TResult 参数指定的类型的值。

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

类型参数

TResult

此委托封装的方法的返回值类型。

这是协变类型参数。 即,可以使用指定的类型,也可以使用派生程度较高的任何类型。 有关协变和逆变的详细信息,请参阅泛型中的协变和逆变

返回值

TResult

此委托封装的方法的返回值。

示例

下面的示例演示如何使用不带参数的委托。 此代码创建一个名为具有 LazyValue 类型 Func<TResult>字段的泛型类。 此委托字段可以存储对任何返回与对象类型参数对应的类型的值的函数的 LazyValue 引用。 如果尚未执行函数) 并返回生成的值,该 LazyValue 类型还具有执行 Value 函数 (的属性。

此示例创建两种方法,并使用调用这些方法的 lambda 表达式实例化两 LazyValue 个对象。 lambda 表达式不采用参数,因为它们只需要调用方法。 如输出所示,仅当检索每个 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中,声明为FunctionSub) ,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;
      }
   }
}

可以将委托与 C# 中的匿名方法配合使用 Func<TResult> ,如以下示例所示。 (有关匿名方法简介,请参阅 Anonymous Methods.)

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;
      }
   }
}

还可以将 lambda 表达式分配给 Func<T,TResult> 委托,如以下示例所示。 (有关 lambda 表达式简介,请参阅 Lambda 表达式 (VB) Lambda 表达式 (C#) ,以及 lambda 表达式 (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;
      }
   }
}

lambda 表达式的基础类型是泛型 Func 委托之一。 这样就可以将 lambda 表达式作为参数传递,而无需将其显式分配给委托。 具体而言,由于命名空间中的 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

另请参阅