閱讀英文版本

分享方式:


Func<TResult> 代理人

定義

封裝沒有參數並傳回 TResult 參數所指定之類型值的方法。

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

類型參數

TResult

這個委派所封裝之方法的傳回值之類型。

這是共變數的型別參數。 也就是說,您可以使用您指定的類型,或衍生程度較高的任何類型。 如需共變數與反變數的詳細資訊,請參閱泛型中的共變數與反變數

傳回值

TResult

這個委派所封裝之方法的傳回值。

範例

下列範例示範如何使用不採用任何參數的委派。 此程式碼會建立名為 LazyValue 的泛型類別,此類別具有 類型的 Func<TResult> 欄位。 這個委派欄位可以儲存任何函式的參考,該函式會傳回對應至 物件之 type 參數 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 中宣告為 Sub ,而不是宣告為 Function) ,請改用 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 參數,所以您可以傳遞這些方法 Lambda 運算式,而不需明確具現化 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

另請參閱