Func<TResult> 代理人

定義

パラメーターを持たないメソッドをカプセル化し、 TResult パラメーターで指定された型の値を返します。

generic <typename TResult>
public delegate TResult Func();
public delegate TResult Func<out TResult>();
public delegate TResult Func<out TResult>() where TResult : allows ref struct;
public delegate TResult Func<TResult>();
type Func<'Result> = delegate of unit -> 'Result
Public Delegate Function Func(Of Out TResult)() As TResult 
Public Delegate Function Func(Of TResult)() As TResult 

型パラメーター

TResult

このデリゲートがカプセル化するメソッドの戻り値の型。

この型パラメーターは共変です。 つまり、指定した型、または強い派生型のいずれかを使用することができます。 共変性および反変性の詳細については、「ジェネリックの共変性と反変性」をご覧ください。

戻り値

TResult

このデリゲートがカプセル化するメソッドの戻り値。

次の例では、パラメーターを受け取っていないデリゲートを使用する方法を示します。 このコードは、Func<TResult>型のフィールドを持つ LazyValue という名前のジェネリック クラスを作成します。 このデリゲート フィールドには、 LazyValue オブジェクトの型パラメーターに対応する型の値を返す任意の関数への参照を格納できます。 LazyValue型には、関数を実行し (まだ実行されていない場合)、結果の値を返すValue プロパティもあります。

この例では、2 つのメソッドを作成し、これらのメソッドを呼び出すラムダ式を使用して 2 つの LazyValue オブジェクトをインスタンス化します。 ラムダ式は、単にメソッドを呼び出す必要があるため、パラメーターを受け取りません。 出力が示すように、2 つのメソッドは、各 LazyValue オブジェクトの値が取得されたときにのみ実行されます。

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
*/
open System

type LazyValue<'T>(func: Func<'T>) =
    let mutable value = ValueNone

    member _.Value =
        match value with
        | ValueSome v -> v
        | ValueNone ->
            // Execute the delegate.
            let v = func.Invoke()
            value <- ValueSome v
            v

let expensiveOne () =
    printfn "\nExpensiveOne() is executing."
    1

let expensiveTwo (input: string) =
    printfn "\nExpensiveTwo() is executing."
    int64 input.Length

// Note that each lambda expression has no parameters.
let lazyOne = LazyValue(fun () -> expensiveOne ())
let lazyTwo = LazyValue(fun () -> expensiveTwo "apple")

printfn "LazyValue objects have been created."

// Get the values of the LazyValue objects.
printfn $"{lazyOne.Value}"
printfn $"{lazyTwo.Value}"


// The example produces the following output:
//     LazyValue objects have been created.
//
//     ExpensiveOne() is executing.
//     1
//
//     ExpensiveTwo() is executing.
//     5
Public Module Func
   Public Sub Main()
      ' Note that each lambda expression has no parameters.
      Dim lazyOne As New LazyValue(Of Integer)(Function() ExpensiveOne())
      Dim lazyTwo As New LazyValue(Of Long)(Function() ExpensiveTwo("apple")) 

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

      ' Get the values of the LazyValue objects.
      Console.WriteLine(lazyOne.Value)
      Console.WriteLine(lazyTwo.Value)
   End Sub

   Public Function ExpensiveOne() As Integer
      Console.WriteLine()
      Console.WriteLine("ExpensiveOne() is executing.")
      Return 1
   End Function

   Public Function ExpensiveTwo(input As String) As Long
      Console.WriteLine() 
      Console.WriteLine("ExpensiveTwo() is executing.")
      Return input.Length
   End Function
End Module

Public Class LazyValue(Of T As Structure)
   Private val As Nullable(Of T)
   Private getValue As Func(Of T)

   ' Constructor.
   Public Sub New(func As Func(Of T))
      Me.val = Nothing
      Me.getValue = func
   End Sub

   Public ReadOnly Property Value() As T
      Get
         If Me.val Is Nothing Then
            ' Execute the delegate.
            Me.val = Me.getValue()
         End If   
         Return CType(val, T)
      End Get
   End Property
End Class

注釈

このデリゲートを使用すると、カスタム デリゲートを明示的に宣言せずにパラメーターとして渡すことができるメソッドを表すことができます。 カプセル化されたメソッドは、このデリゲートによって定義されているメソッド シグネチャに対応している必要があります。 つまり、カプセル化されたメソッドにはパラメーターがなく、値を返す必要があります。

パラメーターを持たず、void (F# では unit) を返すメソッド (または、Function としてではなく、Sub として宣言されているVisual Basic) を参照するには、代わりに Action デリゲートを使用します。

Func<TResult> デリゲートを使用する場合、パラメーターなしのメソッドをカプセル化するデリゲートを明示的に定義する必要はありません。 たとえば、次のコードでは、 WriteMethod という名前のデリゲートを明示的に宣言し、 OutputTarget.SendToFile インスタンス メソッドへの参照をデリゲート インスタンスに割り当てます。

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;
      }
   }
}
open System.IO

type WriteMethod = delegate of unit -> bool

type OutputTarget() =
    member _.SendToFile() =
        try
            let fn = Path.GetTempFileName()
            use sw = new StreamWriter(fn)
            sw.WriteLine "Hello, World!"
            true
        with _ ->
            false

let output = new OutputTarget()
let methodCall = WriteMethod output.SendToFile
if methodCall.Invoke() then
    printfn "Success!"
else
    printfn "File write operation failed."
Imports System.IO

Delegate Function WriteMethod As Boolean

Module TestDelegate
   Public Sub Main()
      Dim output As New OutputTarget()
      Dim methodCall As WriteMethod = AddressOf output.SendToFile
      If methodCall() Then 
         Console.WriteLine("Success!")
      Else
         Console.WriteLine("File write operation failed.")
      End If      
   End Sub
End Module

Public Class OutputTarget
   Public Function SendToFile() As Boolean
      Try
         Dim fn As String = Path.GetTempFileName
         Dim sw As StreamWriter = New StreamWriter(fn)
         sw.WriteLine("Hello, World!")
         sw.Close      
         Return True
      Catch
         Return False
      End Try
   End Function
End Class

次の例では、新しいデリゲートを明示的に定義して名前付きメソッドを割り当てるのではなく、 Func<TResult> デリゲートをインスタンス化することで、このコードを簡略化します。

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;
      }
   }
}
open System
open System.IO

type OutputTarget() =
    member _.SendToFile() =
        try
            let fn = Path.GetTempFileName()
            use sw = new StreamWriter(fn)
            sw.WriteLine "Hello, World!"
            true
        with _ ->
            false

let output = OutputTarget()
let methodCall = Func<bool> output.SendToFile
if methodCall.Invoke() then
    printfn "Success!"
else
    printfn "File write operation failed."
Imports System.IO

Module TestDelegate
   Public Sub Main()
      Dim output As New OutputTarget()
      Dim methodCall As Func(Of Boolean) = AddressOf output.SendToFile
      If methodCall() Then 
         Console.WriteLine("Success!")
      Else
         Console.WriteLine("File write operation failed.")
      End If      
   End Sub
End Module

Public Class OutputTarget
   Public Function SendToFile() As Boolean
      Try
         Dim fn As String = Path.GetTempFileName
         Dim sw As StreamWriter = New StreamWriter(fn)
         sw.WriteLine("Hello, World!")
         sw.Close      
         Return True
      Catch
         Return False
      End Try
   End Function
End Class

次の例に示すように、 Func<TResult> デリゲートを 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#)」を参照してください)。

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;
      }
   }
}
open System
open System.IO

type OutputTarget() =
    member _.SendToFile() =
        try
            let fn = Path.GetTempFileName()
            use sw = new StreamWriter(fn)
            sw.WriteLine "Hello, World!"
            true
        with _ ->
            false

let output = OutputTarget()
let methodCall = Func<bool>(fun () -> output.SendToFile())
if methodCall.Invoke() then
    printfn "Success!"
else
    printfn "File write operation failed."
Imports System.IO

Module TestDelegate
   Public Sub Main()
      Dim output As New OutputTarget()
      Dim methodCall As Func(Of Boolean) = Function() output.SendToFile()
      If methodCall() Then 
         Console.WriteLine("Success!")
      Else
         Console.WriteLine("File write operation failed.")
      End If      
   End Sub
End Module

Public Class OutputTarget
   Public Function SendToFile() As Boolean
      Try
         Dim fn As String = Path.GetTempFileName
         Dim sw As StreamWriter = New StreamWriter(fn)
         sw.WriteLine("Hello, World!")
         sw.Close      
         Return True
      Catch
         Return False
      End Try
   End Function
End Class

ラムダ式の基になる型は、ジェネリック Func デリゲートの 1 つです。 これにより、デリゲートに明示的に割り当てることなく、ラムダ式をパラメーターとして渡すことができます。 特に、 System.Linq 名前空間の型の多くのメソッドには Func パラメーターがあるため、 Func デリゲートを明示的にインスタンス化することなく、これらのメソッドにラムダ式を渡すことができます。

結果が実際に必要な場合にのみ実行するコストの高い計算がある場合は、コストの高い関数を Func<TResult> デリゲートに割り当てることができます。 その後、値にアクセスするプロパティが式で使用されるまで、関数の実行を遅延させることができます。 次のセクションの例では、これを行う方法を示します。

拡張メソッド

名前 説明
GetMethodInfo(Delegate)

指定したデリゲートによって表されるメソッドを表すオブジェクトを取得します。

適用対象

こちらもご覧ください