Delegate 类
定义
重要
一些信息与预发行产品相关,相应产品在发行之前可能会进行重大修改。 对于此处提供的信息,Microsoft 不作任何明示或暗示的担保。
表示委托,它是引用静态方法或类实例和该类的实例方法的数据结构。
public ref class Delegate abstract
public ref class Delegate abstract : ICloneable, System::Runtime::Serialization::ISerializable
public abstract class Delegate
public abstract class Delegate : ICloneable, System.Runtime.Serialization.ISerializable
[System.Runtime.InteropServices.ClassInterface(System.Runtime.InteropServices.ClassInterfaceType.AutoDual)]
[System.Serializable]
public abstract class Delegate : ICloneable, System.Runtime.Serialization.ISerializable
[System.Runtime.InteropServices.ClassInterface(System.Runtime.InteropServices.ClassInterfaceType.AutoDual)]
[System.Serializable]
[System.Runtime.InteropServices.ComVisible(true)]
public abstract class Delegate : ICloneable, System.Runtime.Serialization.ISerializable
type Delegate = class
type Delegate = class
interface ICloneable
interface ISerializable
[<System.Runtime.InteropServices.ClassInterface(System.Runtime.InteropServices.ClassInterfaceType.AutoDual)>]
[<System.Serializable>]
type Delegate = class
interface ICloneable
interface ISerializable
[<System.Runtime.InteropServices.ClassInterface(System.Runtime.InteropServices.ClassInterfaceType.AutoDual)>]
[<System.Serializable>]
[<System.Runtime.InteropServices.ComVisible(true)>]
type Delegate = class
interface ICloneable
interface ISerializable
Public MustInherit Class Delegate
Public MustInherit Class Delegate
Implements ICloneable, ISerializable
- 继承
-
Delegate
- 派生
- 属性
- 实现
示例
本部分包含两个代码示例。 第一个示例演示了可以使用此方法重载创建的两种类型的委托:在实例方法上打开并打开静态方法。
第二个代码示例演示了兼容的参数类型和返回类型。
示例 1
以下代码示例演示了使用 CreateDelegate 方法的这个重载来创建委托的两种方式。
注释
CreateDelegate 方法有两个重载,它们指定一个 MethodInfo 但没有指定第一个参数;它们的功能相同,只是其中一个允许你指定在绑定失败时是否引发异常,而另一个则始终会引发异常。 此代码示例使用这两个重载。
该示例声明类C,带有静态方法M2和实例方法M1,以及两种委托类型:D1 使用类的实例C和一个字符串,D2 使用一个字符串。
第二个名为Example的类包含用于创建委托的代码。
- 为实例方法
D1创建了一个类型为M1的委托,代表一个开放实例方法。 调用委托时必须传递一个实例。 - 为静态方法
D2创建类型M2的委托,该委托表示开放的静态方法。
using System;
using System.Reflection;
// Declare three delegate types for demonstrating the combinations
// of static versus instance methods and open versus closed
// delegates.
//
public delegate void D1(C c, string s);
public delegate void D2(string s);
public delegate void D3();
// A sample class with an instance method and a static method.
//
public class C
{
private int id;
public C(int id) { this.id = id; }
public void M1(string s) =>
Console.WriteLine($"Instance method M1 on C: id = {this.id}, s = {s}");
public static void M2(string s)
{
Console.WriteLine($"Static method M2 on C: s = {s}");
}
}
public class Example2
{
public static void Main()
{
C c1 = new C(42);
// Get a MethodInfo for each method.
//
MethodInfo mi1 = typeof(C).GetMethod("M1",
BindingFlags.Public | BindingFlags.Instance);
MethodInfo mi2 = typeof(C).GetMethod("M2",
BindingFlags.Public | BindingFlags.Static);
D1 d1;
D2 d2;
D3 d3;
Console.WriteLine("\nAn instance method closed over C.");
// In this case, the delegate and the
// method must have the same list of argument types; use
// delegate type D2 with instance method M1.
//
Delegate test =
Delegate.CreateDelegate(typeof(D2), c1, mi1, false);
// Because false was specified for throwOnBindFailure
// in the call to CreateDelegate, the variable 'test'
// contains null if the method fails to bind (for
// example, if mi1 happened to represent a method of
// some class other than C).
//
if (test != null)
{
d2 = (D2)test;
// The same instance of C is used every time the
// delegate is invoked.
d2("Hello, World!");
d2("Hi, Mom!");
}
Console.WriteLine("\nAn open instance method.");
// In this case, the delegate has one more
// argument than the instance method; this argument comes
// at the beginning, and represents the hidden instance
// argument of the instance method. Use delegate type D1
// with instance method M1.
//
d1 = (D1)Delegate.CreateDelegate(typeof(D1), null, mi1);
// An instance of C must be passed in each time the
// delegate is invoked.
//
d1(c1, "Hello, World!");
d1(new C(5280), "Hi, Mom!");
Console.WriteLine("\nAn open static method.");
// In this case, the delegate and the method must
// have the same list of argument types; use delegate type
// D2 with static method M2.
//
d2 = (D2)Delegate.CreateDelegate(typeof(D2), null, mi2);
// No instances of C are involved, because this is a static
// method.
//
d2("Hello, World!");
d2("Hi, Mom!");
Console.WriteLine("\nA static method closed over the first argument (String).");
// The delegate must omit the first argument of the method.
// A string is passed as the firstArgument parameter, and
// the delegate is bound to this string. Use delegate type
// D3 with static method M2.
//
d3 = (D3)Delegate.CreateDelegate(typeof(D3),
"Hello, World!", mi2);
// Each time the delegate is invoked, the same string is
// used.
d3();
}
}
/* This code example produces the following output:
An instance method closed over C.
Instance method M1 on C: id = 42, s = Hello, World!
Instance method M1 on C: id = 42, s = Hi, Mom!
An open instance method.
Instance method M1 on C: id = 42, s = Hello, World!
Instance method M1 on C: id = 5280, s = Hi, Mom!
An open static method.
Static method M2 on C: s = Hello, World!
Static method M2 on C: s = Hi, Mom!
A static method closed over the first argument (String).
Static method M2 on C: s = Hello, World!
*/
open System
open System.Reflection
// A sample class with an instance method and a static method.
type C(id) =
member _.M1(s) =
printfn $"Instance method M1 on C: id = %i{id}, s = %s{s}"
static member M2(s) =
printfn $"Static method M2 on C: s = %s{s}"
// Declare three delegate types for demonstrating the combinations
// of static versus instance methods and open versus closed
// delegates.
type D1 = delegate of C * string -> unit
type D2 = delegate of string -> unit
type D3 = delegate of unit -> unit
let c1 = C 42
// Get a MethodInfo for each method.
//
let mi1 = typeof<C>.GetMethod("M1", BindingFlags.Public ||| BindingFlags.Instance)
let mi2 = typeof<C>.GetMethod("M2", BindingFlags.Public ||| BindingFlags.Static)
printfn "\nAn instance method closed over C."
// In this case, the delegate and the
// method must have the same list of argument types use
// delegate type D2 with instance method M1.
let test = Delegate.CreateDelegate(typeof<D2>, c1, mi1, false)
// Because false was specified for throwOnBindFailure
// in the call to CreateDelegate, the variable 'test'
// contains null if the method fails to bind (for
// example, if mi1 happened to represent a method of
// some class other than C).
if test <> null then
let d2 = test :?> D2
// The same instance of C is used every time the
// delegate is invoked.
d2.Invoke "Hello, World!"
d2.Invoke "Hi, Mom!"
printfn "\nAn open instance method."
// In this case, the delegate has one more
// argument than the instance method this argument comes
// at the beginning, and represents the hidden instance
// argument of the instance method. Use delegate type D1
// with instance method M1.
let d1 = Delegate.CreateDelegate(typeof<D1>, null, mi1) :?> D1
// An instance of C must be passed in each time the
// delegate is invoked.
d1.Invoke(c1, "Hello, World!")
d1.Invoke(C 5280, "Hi, Mom!")
printfn "\nAn open static method."
// In this case, the delegate and the method must
// have the same list of argument types use delegate type
// D2 with static method M2.
let d2 = Delegate.CreateDelegate(typeof<D2>, null, mi2) :?> D2
// No instances of C are involved, because this is a static
// method.
d2.Invoke "Hello, World!"
d2.Invoke "Hi, Mom!"
printfn "\nA static method closed over the first argument (String)."
// The delegate must omit the first argument of the method.
// A string is passed as the firstArgument parameter, and
// the delegate is bound to this string. Use delegate type
// D3 with static method M2.
let d3 = Delegate.CreateDelegate(typeof<D3>, "Hello, World!", mi2) :?> D3
// Each time the delegate is invoked, the same string is used.
d3.Invoke()
// This code example produces the following output:
// An instance method closed over C.
// Instance method M1 on C: id = 42, s = Hello, World!
// Instance method M1 on C: id = 42, s = Hi, Mom!
//
// An open instance method.
// Instance method M1 on C: id = 42, s = Hello, World!
// Instance method M1 on C: id = 5280, s = Hi, Mom!
//
// An open static method.
// Static method M2 on C: s = Hello, World!
// Static method M2 on C: s = Hi, Mom!
//
// A static method closed over the first argument (String).
// Static method M2 on C: s = Hello, World!
Imports System.Reflection
Imports System.Security.Permissions
' Declare three delegate types for demonstrating the combinations
' of Shared versus instance methods and open versus closed
' delegates.
'
Public Delegate Sub D1(ByVal c As C2, ByVal s As String)
Public Delegate Sub D2(ByVal s As String)
Public Delegate Sub D3()
' A sample class with an instance method and a Shared method.
'
Public Class C2
Private id As Integer
Public Sub New(ByVal id As Integer)
Me.id = id
End Sub
Public Sub M1(ByVal s As String)
Console.WriteLine("Instance method M1 on C2: id = {0}, s = {1}",
Me.id, s)
End Sub
Public Shared Sub M2(ByVal s As String)
Console.WriteLine("Shared method M2 on C2: s = {0}", s)
End Sub
End Class
Public Class Example2
Public Shared Sub Main()
Dim c1 As New C2(42)
' Get a MethodInfo for each method.
'
Dim mi1 As MethodInfo = GetType(C2).GetMethod("M1",
BindingFlags.Public Or BindingFlags.Instance)
Dim mi2 As MethodInfo = GetType(C2).GetMethod("M2",
BindingFlags.Public Or BindingFlags.Static)
Dim d1 As D1
Dim d2 As D2
Dim d3 As D3
Console.WriteLine(vbLf & "An instance method closed over C2.")
' In this case, the delegate and the
' method must have the same list of argument types; use
' delegate type D2 with instance method M1.
'
Dim test As [Delegate] =
[Delegate].CreateDelegate(GetType(D2), c1, mi1, False)
' Because False was specified for throwOnBindFailure
' in the call to CreateDelegate, the variable 'test'
' contains Nothing if the method fails to bind (for
' example, if mi1 happened to represent a method of
' some class other than C2).
'
If test IsNot Nothing Then
d2 = CType(test, D2)
' The same instance of C2 is used every time the
' delegate is invoked.
d2("Hello, World!")
d2("Hi, Mom!")
End If
Console.WriteLine(vbLf & "An open instance method.")
' In this case, the delegate has one more
' argument than the instance method; this argument comes
' at the beginning, and represents the hidden instance
' argument of the instance method. Use delegate type D1
' with instance method M1.
'
d1 = CType([Delegate].CreateDelegate(GetType(D1), Nothing, mi1), D1)
' An instance of C2 must be passed in each time the
' delegate is invoked.
'
d1(c1, "Hello, World!")
d1(New C2(5280), "Hi, Mom!")
Console.WriteLine(vbLf & "An open Shared method.")
' In this case, the delegate and the method must
' have the same list of argument types; use delegate type
' D2 with Shared method M2.
'
d2 = CType([Delegate].CreateDelegate(GetType(D2), Nothing, mi2), D2)
' No instances of C2 are involved, because this is a Shared
' method.
'
d2("Hello, World!")
d2("Hi, Mom!")
Console.WriteLine(vbLf & "A Shared method closed over the first argument (String).")
' The delegate must omit the first argument of the method.
' A string is passed as the firstArgument parameter, and
' the delegate is bound to this string. Use delegate type
' D3 with Shared method M2.
'
d3 = CType([Delegate].CreateDelegate(GetType(D3), "Hello, World!", mi2), D3)
' Each time the delegate is invoked, the same string is
' used.
d3()
End Sub
End Class
' This code example produces the following output:
'
'An instance method closed over C2.
'Instance method M1 on C2: id = 42, s = Hello, World!
'Instance method M1 on C2: id = 42, s = Hi, Mom!
'
'An open instance method.
'Instance method M1 on C2: id = 42, s = Hello, World!
'Instance method M1 on C2: id = 5280, s = Hi, Mom!
'
'An open Shared method.
'Shared method M2 on C2: s = Hello, World!
'Shared method M2 on C2: s = Hi, Mom!
'
'A Shared method closed over the first argument (String).
'Shared method M2 on C2: s = Hello, World!
'
示例 2
下面的代码示例演示参数类型和返回类型的兼容性。
该代码示例定义了一个基类,命名为 Base,以及一个命名为 Derived 的类继承自 Base。 派生类有一个名为 static的 Shared(在 Visual Basic 中为 MyMethod)方法,该方法有一个类型为 Base 的参数,返回类型为 Derived。 该代码示例还定义了一个名为 Example 的委托,该委托具有一个类型为 Derived 的参数和一个类型为 Base 的返回值。
代码示例演示如何使用命名 Example 的委托来表示方法 MyMethod。 该方法可以绑定到委托,原因如下:
- 委托()的参数类型比 (
DerivedMyMethod) 的参数类型Base更严格,以便始终安全地将委托的参数传递给MyMethod。 -
MyMethod(Derived) 的返回类型比委托 (Base) 的参数类型更严格,因此将方法的返回类型强制转换为委托的返回类型始终是安全的。
该代码示例不生成任何输出。
using System;
using System.Reflection;
// Define two classes to use in the demonstration, a base class and
// a class that derives from it.
//
public class Base { }
public class Derived : Base
{
// Define a static method to use in the demonstration. The method
// takes an instance of Base and returns an instance of Derived.
// For the purposes of the demonstration, it is not necessary for
// the method to do anything useful.
//
public static Derived MyMethod(Base arg)
{
Base dummy = arg;
return new Derived();
}
}
// Define a delegate that takes an instance of Derived and returns an
// instance of Base.
//
public delegate Base Example5(Derived arg);
class Test
{
public static void Main()
{
// The binding flags needed to retrieve MyMethod.
BindingFlags flags = BindingFlags.Public | BindingFlags.Static;
// Get a MethodInfo that represents MyMethod.
MethodInfo minfo = typeof(Derived).GetMethod("MyMethod", flags);
// Demonstrate contravariance of parameter types and covariance
// of return types by using the delegate Example5 to represent
// MyMethod. The delegate binds to the method because the
// parameter of the delegate is more restrictive than the
// parameter of the method (that is, the delegate accepts an
// instance of Derived, which can always be safely passed to
// a parameter of type Base), and the return type of MyMethod
// is more restrictive than the return type of Example5 (that
// is, the method returns an instance of Derived, which can
// always be safely cast to type Base).
//
Example5 ex =
(Example5)Delegate.CreateDelegate(typeof(Example5), minfo);
// Execute MyMethod using the delegate Example5.
//
Base b = ex(new Derived());
}
}
open System
open System.Reflection
// Define two classes to use in the demonstration, a base class and
// a class that derives from it.
type Base() = class end
type Derived() =
inherit Base()
// Define a static method to use in the demonstration. The method
// takes an instance of Base and returns an instance of Derived.
// For the purposes of the demonstration, it is not necessary for
// the method to do anything useful.
static member MyMethod(arg: Base) =
Derived()
// Define a delegate that takes an instance of Derived and returns an
// instance of Base.
type Example = delegate of Derived -> Base
// The binding flags needed to retrieve MyMethod.
let flags = BindingFlags.Public ||| BindingFlags.Static
// Get a MethodInfo that represents MyMethod.
let minfo = typeof<Derived>.GetMethod("MyMethod", flags)
// Demonstrate contravariance of parameter types and covariance
// of return types by using the delegate Example to represent
// MyMethod. The delegate binds to the method because the
// parameter of the delegate is more restrictive than the
// parameter of the method (that is, the delegate accepts an
// instance of Derived, which can always be safely passed to
// a parameter of type Base), and the return type of MyMethod
// is more restrictive than the return type of Example (that
// is, the method returns an instance of Derived, which can
// always be safely cast to type Base).
let ex = Delegate.CreateDelegate(typeof<Example>, minfo) :?> Example
// Execute MyMethod using the delegate Example.
let b = Derived() |> ex.Invoke
Imports System.Reflection
' Define two classes to use in the demonstration, a base class and
' a class that derives from it.
'
Public Class Base
End Class
Public Class Derived
Inherits Base
' Define a Shared method to use in the demonstration. The method
' takes an instance of Base and returns an instance of Derived.
' For the purposes of the demonstration, it is not necessary for
' the method to do anything useful.
'
Public Shared Function MyMethod(ByVal arg As Base) As Derived
Dim dummy As Base = arg
Return New Derived()
End Function
End Class
' Define a delegate that takes an instance of Derived and returns an
' instance of Base.
'
Public Delegate Function Example(ByVal arg As Derived) As Base
Module Test
Sub Main()
' The binding flags needed to retrieve MyMethod.
Dim flags As BindingFlags = _
BindingFlags.Public Or BindingFlags.Static
' Get a MethodInfo that represents MyMethod.
Dim minfo As MethodInfo = _
GetType(Derived).GetMethod("MyMethod", flags)
' Demonstrate contravariance of parameter types and covariance
' of return types by using the delegate Example to represent
' MyMethod. The delegate binds to the method because the
' parameter of the delegate is more restrictive than the
' parameter of the method (that is, the delegate accepts an
' instance of Derived, which can always be safely passed to
' a parameter of type Base), and the return type of MyMethod
' is more restrictive than the return type of Example (that
' is, the method returns an instance of Derived, which can
' always be safely cast to type Base).
'
Dim ex As Example = CType( _
[Delegate].CreateDelegate(GetType(Example), minfo), _
Example _
)
' Execute MyMethod using the delegate Example.
'
Dim b As Base = ex(New Derived())
End Sub
End Module
CreateDelegate(Type, Object, MethodInfo) 和 CreateDelegate(Type, Object, MethodInfo, Boolean) 方法
这两个重载的功能相同,只是其中一个允许你指定在绑定失败时是否引发异常,而另一个则始终会引发异常。
委托类型和方法必须具有兼容的返回类型。 也就是说,method 的返回类型必须可以赋值给 type 的返回类型。
firstArgument,这些重载的第二个参数是委托表示的方法的第一个参数。 如果提供了 firstArgument,那么每次调用委托时它都会被传递给 method;此时可以说 firstArgument 绑定到了该委托,并且称该委托在其第一个参数上形成闭包。 如果 method 为 static (Shared 在 Visual Basic 中),则调用委托时提供的参数列表包括除第一个参数以外的所有参数;如果是 method 实例方法,则 firstArgument 传递给隐藏实例参数(在 this C# 中或 Me Visual Basic 中表示)。
如果 firstArgument 提供,则第一个参数 method 必须是引用类型,并且 firstArgument 必须与该类型兼容。
Important
如果 method 为 static (Shared 在 Visual Basic 中)及其第一个参数的类型 Object , ValueType则 firstArgument 可以是值类型。 在这种情况下 firstArgument 会自动装箱。 与在 C# 或 Visual Basic 函数调用中一样,对于任何其他参数都不会发生自动装箱。
如果 firstArgument 是 null 引用,并且 method 是实例方法,则结果取决于委托类型 type 和 method 的签名。
- 如果
type的签名显式包含method的第一个隐藏参数,则称该委托表示一个开放实例方法。 调用委托时,参数列表中的第一个参数将传递给隐藏的method实例参数。 - 如果签名
method和type匹配(即所有参数类型都兼容),则称该委托在空引用上形成闭包。 调用委托就像对 null 实例调用实例方法一样,这不是一件特别有用的事情。
如果 firstArgument 为 null 引用且 method 是静态的,则结果取决于委托类型 type 和 method 的签名。
- 如果签名
method和type匹配(即所有参数类型都兼容),则表示委托表示开放静态方法。 这是静态方法最常见的情况。 在这种情况下,通过使用CreateDelegate(Type, MethodInfo) 方法重载可以获得更好的性能。 - 如果
type的签名以method的第二个参数开头,并且其余参数类型兼容,则称该委托在空引用上形成闭包。 调用委托时,向第一个参数method传递空引用。
示例
下面的代码示例演示单个委托类型可以表示的所有方法:在实例方法上关闭、在实例方法上打开、在静态方法上打开,并通过静态方法关闭。
该代码示例定义了两个类C和F,以及一个具有D类型参数的委托类型C。 这些类具有匹配的静态和实例方法 M1, M3并且 M4类 C 也具有没有参数的实例方法 M2 。
名为 Example 的第三个类包含创建委托的代码。
- 为类型
M1和类型C的实例方法F创建委托;每个委托都在各自类型的一个实例上形成闭包。 类型为M1的方法C显示绑定实例和参数的ID属性。 - 为类型
M2的方法C创建一个委托。 这是一个开放实例委托,其中委托的参数表示实例方法上隐藏的第一个参数。 该方法没有其他参数。 它的调用方式就像是调用一个静态方法。 - 为类型
M3和类型C的静态方法F创建委托;这些是开放的静态委托。 - 最后,为类型
M4和类型C的静态方法F创建委托;每个方法都将声明类型作为其第一个参数,并提供该类型的一个实例,因此这些委托在其第一个参数上形成闭包。 类型为M4的方法C显示绑定实例和参数的ID属性。
using System;
using System.Reflection;
// Declare a delegate type. The object of this code example
// is to show all the methods this delegate can bind to.
//
public delegate void D(C1 c);
// Declare two sample classes, C1 and F. Class C1 has an ID
// property so instances can be identified.
//
public class C1
{
private int id;
public int ID => id;
public C1(int id) => this.id = id;
public void M1(C1 c)
{
Console.WriteLine("Instance method M1(C1 c) on C1: this.id = {0}, c.ID = {1}",
this.id, c.ID);
}
public void M2()
{
Console.WriteLine($"Instance method M2() on C1: this.id = {this.id}");
}
public static void M3(C1 c)
{
Console.WriteLine($"Static method M3(C1 c) on C1: c.ID = {c.ID}");
}
public static void M4(C1 c1, C1 c2)
{
Console.WriteLine("Static method M4(C1 c1, C1 c2) on C1: c1.ID = {0}, c2.ID = {1}",
c1.ID, c2.ID);
}
}
public class F
{
public void M1(C1 c)
{
Console.WriteLine($"Instance method M1(C1 c) on F: c.ID = {c.ID}");
}
public static void M3(C1 c)
{
Console.WriteLine($"Static method M3(C1 c) on F: c.ID = {c.ID}");
}
public static void M4(F f, C1 c)
{
Console.WriteLine($"Static method M4(F f, C1 c) on F: c.ID = {c.ID}");
}
}
public class Example
{
public static void Main()
{
C1 c1 = new (42);
C1 c2 = new (1491);
F f1 = new ();
D d;
// Instance method with one argument of type C1.
MethodInfo cmi1 = typeof(C1).GetMethod("M1");
// Instance method with no arguments.
MethodInfo cmi2 = typeof(C1).GetMethod("M2");
// Static method with one argument of type C1.
MethodInfo cmi3 = typeof(C1).GetMethod("M3");
// Static method with two arguments of type C1.
MethodInfo cmi4 = typeof(C1).GetMethod("M4");
// Instance method with one argument of type C1.
MethodInfo fmi1 = typeof(F).GetMethod("M1");
// Static method with one argument of type C1.
MethodInfo fmi3 = typeof(F).GetMethod("M3");
// Static method with an argument of type F and an argument
// of type C1.
MethodInfo fmi4 = typeof(F).GetMethod("M4");
Console.WriteLine("\nAn instance method on any type, with an argument of type C1.");
// D can represent any instance method that exactly matches its
// signature. Methods on C1 and F are shown here.
//
d = (D)Delegate.CreateDelegate(typeof(D), c1, cmi1);
d(c2);
d = (D)Delegate.CreateDelegate(typeof(D), f1, fmi1);
d(c2);
Console.WriteLine("\nAn instance method on C1 with no arguments.");
// D can represent an instance method on C1 that has no arguments;
// in this case, the argument of D represents the hidden first
// argument of any instance method. The delegate acts like a
// static method, and an instance of C1 must be passed each time
// it is invoked.
//
d = (D)Delegate.CreateDelegate(typeof(D), null, cmi2);
d(c1);
Console.WriteLine("\nA static method on any type, with an argument of type C1.");
// D can represent any static method with the same signature.
// Methods on F and C1 are shown here.
//
d = (D)Delegate.CreateDelegate(typeof(D), null, cmi3);
d(c1);
d = (D)Delegate.CreateDelegate(typeof(D), null, fmi3);
d(c1);
Console.WriteLine("\nA static method on any type, with an argument of");
Console.WriteLine(" that type and an argument of type C1.");
// D can represent any static method with one argument of the
// type the method belongs and a second argument of type C1.
// In this case, the method is closed over the instance of
// supplied for the its first argument, and acts like an instance
// method. Methods on F and C1 are shown here.
//
d = (D)Delegate.CreateDelegate(typeof(D), c1, cmi4);
d(c2);
Delegate test =
Delegate.CreateDelegate(typeof(D), f1, fmi4, false);
// This final example specifies false for throwOnBindFailure
// in the call to CreateDelegate, so the variable 'test'
// contains Nothing if the method fails to bind (for
// example, if fmi4 happened to represent a method of
// some class other than F).
//
if (test != null)
{
d = (D)test;
d(c2);
}
}
}
/* This code example produces the following output:
An instance method on any type, with an argument of type C1.
Instance method M1(C1 c) on C1: this.id = 42, c.ID = 1491
Instance method M1(C1 c) on F: c.ID = 1491
An instance method on C1 with no arguments.
Instance method M2() on C1: this.id = 42
A static method on any type, with an argument of type C1.
Static method M3(C1 c) on C1: c.ID = 42
Static method M3(C1 c) on F: c.ID = 42
A static method on any type, with an argument of
that type and an argument of type C1.
Static method M4(C1 c1, C1 c2) on C1: c1.ID = 42, c2.ID = 1491
Static method M4(F f, C1 c) on F: c.ID = 1491
*/
open System
// Declare two sample classes, C and F. Class C has an ID
// property so instances can be identified.
type C(id) =
member _.ID = id
member _.M1(c: C) =
printfn $"Instance method M1(C c) on C: this.id = {id}, c.ID = {c.ID}"
member _.M2() =
printfn $"Instance method M2() on C: this.id = {id}"
static member M3(c: C) =
printfn $"Static method M3(C c) on C: c.ID = {c.ID}"
static member M4(c1: C, c2: C) =
printfn $"Static method M4(C c1, C c2) on C: c1.ID = {c1.ID}, c2.ID = {c2.ID}"
// Declare a delegate type. The object of this code example
// is to show all the methods this delegate can bind to.
type D = delegate of C -> unit
type F() =
member _.M1(c: C) =
printfn $"Instance method M1(C c) on F: c.ID = {c.ID}"
member _.M3(c: C) =
printfn $"Static method M3(C c) on F: c.ID = {c.ID}"
member _.M4(f: F, c: C) =
printfn $"Static method M4(F f, C c) on F: c.ID = {c.ID}"
[<EntryPoint>]
let main _ =
let c1 = C 42
let c2 = C 1491
let f1 = F()
// Instance method with one argument of type C.
let cmi1 = typeof<C>.GetMethod "M1"
// Instance method with no arguments.
let cmi2 = typeof<C>.GetMethod "M2"
// Static method with one argument of type C.
let cmi3 = typeof<C>.GetMethod "M3"
// Static method with two arguments of type C.
let cmi4 = typeof<C>.GetMethod "M4"
// Instance method with one argument of type C.
let fmi1 = typeof<F>.GetMethod "M1"
// Static method with one argument of type C.
let fmi3 = typeof<F>.GetMethod "M3"
// Static method with an argument of type F and an argument
// of type C.
let fmi4 = typeof<F>.GetMethod "M4"
printfn "\nAn instance method on any type, with an argument of type C."
// D can represent any instance method that exactly matches its
// signature. Methods on C and F are shown here.
let d = Delegate.CreateDelegate(typeof<D>, c1, cmi1) :?> D
d.Invoke c2
let d = Delegate.CreateDelegate(typeof<D>, f1, fmi1) :?> D
d.Invoke c2
Console.WriteLine("\nAn instance method on C with no arguments.")
// D can represent an instance method on C that has no arguments
// in this case, the argument of D represents the hidden first
// argument of any instance method. The delegate acts like a
// static method, and an instance of C must be passed each time
// it is invoked.
let d = Delegate.CreateDelegate(typeof<D>, null, cmi2) :?> D
d.Invoke c1
printfn "\nA static method on any type, with an argument of type C."
// D can represent any static method with the same signature.
// Methods on F and C are shown here.
let d = Delegate.CreateDelegate(typeof<D>, null, cmi3) :?> D
d.Invoke c1
let d = Delegate.CreateDelegate(typeof<D>, null, fmi3) :?> D
d.Invoke c1
printfn "\nA static method on any type, with an argument of"
printfn " that type and an argument of type C."
// D can represent any static method with one argument of the
// type the method belongs and a second argument of type C.
// In this case, the method is closed over the instance of
// supplied for the its first argument, and acts like an instance
// method. Methods on F and C are shown here.
let d = Delegate.CreateDelegate(typeof<D>, c1, cmi4) :?> D
d.Invoke c2
let test =
Delegate.CreateDelegate(typeof<D>, f1, fmi4, false)
// This final example specifies false for throwOnBindFailure
// in the call to CreateDelegate, so the variable 'test'
// contains Nothing if the method fails to bind (for
// example, if fmi4 happened to represent a method of
// some class other than F).
match test with
| :? D as d ->
d.Invoke c2
| _ -> ()
0
// This code example produces the following output:
// An instance method on any type, with an argument of type C.
// Instance method M1(C c) on C: this.id = 42, c.ID = 1491
// Instance method M1(C c) on F: c.ID = 1491
//
// An instance method on C with no arguments.
// Instance method M2() on C: this.id = 42
//
// A static method on any type, with an argument of type C.
// Static method M3(C c) on C: c.ID = 42
// Static method M3(C c) on F: c.ID = 42
//
// A static method on any type, with an argument of
// that type and an argument of type C.
// Static method M4(C c1, C c2) on C: c1.ID = 42, c2.ID = 1491
// Static method M4(F f, C c) on F: c.ID = 1491
Imports System.Reflection
Imports System.Security.Permissions
' Declare a delegate type. The object of this code example
' is to show all the methods this delegate can bind to.
'
Public Delegate Sub D(ByVal c As C)
' Declare two sample classes, C and F. Class C has an ID
' property so instances can be identified.
'
Public Class C
Private _id As Integer
Public ReadOnly Property ID() As Integer
Get
Return _id
End Get
End Property
Public Sub New(ByVal newId As Integer)
Me._id = newId
End Sub
Public Sub M1(ByVal c As C)
Console.WriteLine("Instance method M1(c As C) on C: this.id = {0}, c.ID = {1}", _
Me.id, c.ID)
End Sub
Public Sub M2()
Console.WriteLine("Instance method M2() on C: this.id = {0}", Me.id)
End Sub
Public Shared Sub M3(ByVal c As C)
Console.WriteLine("Shared method M3(c As C) on C: c.ID = {0}", c.ID)
End Sub
Public Shared Sub M4(ByVal c1 As C, ByVal c2 As C)
Console.WriteLine("Shared method M4(c1 As C, c2 As C) on C: c1.ID = {0}, c2.ID = {1}", _
c1.ID, c2.ID)
End Sub
End Class
Public Class F
Public Sub M1(ByVal c As C)
Console.WriteLine("Instance method M1(c As C) on F: c.ID = {0}", c.ID)
End Sub
Public Shared Sub M3(ByVal c As C)
Console.WriteLine("Shared method M3(c As C) on F: c.ID = {0}", c.ID)
End Sub
Public Shared Sub M4(ByVal f As F, ByVal c As C)
Console.WriteLine("Shared method M4(f As F, c As C) on F: c.ID = {0}", c.ID)
End Sub
End Class
Public Class Example5
Public Shared Sub Main()
Dim c1 As New C(42)
Dim c2 As New C(1491)
Dim f1 As New F()
Dim d As D
' Instance method with one argument of type C.
Dim cmi1 As MethodInfo = GetType(C).GetMethod("M1")
' Instance method with no arguments.
Dim cmi2 As MethodInfo = GetType(C).GetMethod("M2")
' Shared method with one argument of type C.
Dim cmi3 As MethodInfo = GetType(C).GetMethod("M3")
' Shared method with two arguments of type C.
Dim cmi4 As MethodInfo = GetType(C).GetMethod("M4")
' Instance method with one argument of type C.
Dim fmi1 As MethodInfo = GetType(F).GetMethod("M1")
' Shared method with one argument of type C.
Dim fmi3 As MethodInfo = GetType(F).GetMethod("M3")
' Shared method with an argument of type F and an
' argument of type C.
Dim fmi4 As MethodInfo = GetType(F).GetMethod("M4")
Console.WriteLine(vbLf & "An instance method on any type, with an argument of type C.")
' D can represent any instance method that exactly matches its
' signature. Methods on C and F are shown here.
'
d = CType([Delegate].CreateDelegate(GetType(D), c1, cmi1), D)
d(c2)
d = CType([Delegate].CreateDelegate(GetType(D), f1, fmi1), D)
d(c2)
Console.WriteLine(vbLf & "An instance method on C with no arguments.")
' D can represent an instance method on C that has no arguments;
' in this case, the argument of D represents the hidden first
' argument of any instance method. The delegate acts like a
' Shared method, and an instance of C must be passed each time
' it is invoked.
'
d = CType([Delegate].CreateDelegate(GetType(D), Nothing, cmi2), D)
d(c1)
Console.WriteLine(vbLf & "A Shared method on any type, with an argument of type C.")
' D can represent any Shared method with the same signature.
' Methods on F and C are shown here.
'
d = CType([Delegate].CreateDelegate(GetType(D), Nothing, cmi3), D)
d(c1)
d = CType([Delegate].CreateDelegate(GetType(D), Nothing, fmi3), D)
d(c1)
Console.WriteLine(vbLf & "A Shared method on any type, with an argument of")
Console.WriteLine(" that type and an argument of type C.")
' D can represent any Shared method with one argument of the
' type the method belongs and a second argument of type C.
' In this case, the method is closed over the instance of
' supplied for the its first argument, and acts like an instance
' method. Methods on F and C are shown here.
'
d = CType([Delegate].CreateDelegate(GetType(D), c1, cmi4), D)
d(c2)
Dim test As [Delegate] =
[Delegate].CreateDelegate(GetType(D), f1, fmi4, False)
' This final example specifies False for throwOnBindFailure
' in the call to CreateDelegate, so the variable 'test'
' contains Nothing if the method fails to bind (for
' example, if fmi4 happened to represent a method of
' some class other than F).
'
If test IsNot Nothing Then
d = CType(test, D)
d(c2)
End If
End Sub
End Class
' This code example produces the following output:
'
'An instance method on any type, with an argument of type C.
'Instance method M1(c As C) on C: this.id = 42, c.ID = 1491
'Instance method M1(c As C) on F: c.ID = 1491
'
'An instance method on C with no arguments.
'Instance method M2() on C: this.id = 42
'
'A Shared method on any type, with an argument of type C.
'Shared method M3(c As C) on C: c.ID = 42
'Shared method M3(c As C) on F: c.ID = 42
'
'A Shared method on any type, with an argument of
' that type and an argument of type C.
'Shared method M4(c1 As C, c2 As C) on C: c1.ID = 42, c2.ID = 1491
'Shared method M4(f As F, c As C) on F: c.ID = 1491
'
兼容的参数类型和返回类型
使用此方法重载创建的委托的参数类型和返回类型必须与委托表示的方法的参数类型和返回类型兼容;类型不必完全匹配。
如果委托的类型比方法参数的类型更严格,则委托参数的参数与方法的相应参数兼容,因为这样可以保证传递给委托的参数可以安全地传递给该方法。
同样,如果方法的返回类型比委托的返回类型更严格,则委托的返回类型与方法的返回类型兼容,因为这样可以保证方法的返回值可以安全地强制转换为委托的返回类型。
例如,具有类型参数 Hashtable 和返回类型 Object 的委托可以表示具有类型参数 Object 和返回值类型 Hashtable 的方法。
确定委托可以代表的方法
考虑CreateDelegate(Type, Object, MethodInfo)重载提供的灵活性的一种有用方式是,任何给定的委托都可以表示方法签名和方法类型(静态与实例)的四种不同组合。 考虑一个具有类型为 D 的参数的委托类型 C。 下面描述了方法 D 能够代表的内容,忽略返回类型,因为它在所有情况下都必须匹配。
D可以表示具有一个类型为C参数的任何实例方法,而不考虑该实例方法属于哪种类型。 当调用 CreateDelegate 时,firstArgument是method所属类型的一个实例,并且称由此生成的委托在该实例上形成闭包。 (简单来说,如果D是一个空引用,firstArgument也可以在空引用上形成闭包。)D可以表示没有参数的C实例方法。 当调用 CreateDelegate 时,firstArgument是空引用。 生成的委托表示一个开放的实例方法,并且每次调用时都必须提供一个C实例。D可以表示采用一个类型的C参数的静态方法,并且该方法可以属于任何类型。 当调用 CreateDelegate 时,firstArgument是空引用。 生成的委托表示一个打开的静态方法,每次调用它时都必须提供一个实例C。D可以表示属于F类型的静态方法,并且具有两个参数,分别属于F类型和C类型。 调用CreateDelegate 时,firstArgument是F的一个实例。 生成的委托表示在F的该实例上形成闭包的静态方法。 请注意,在相同类型的情况下FC,静态方法具有该类型的两个参数。 (在这种情况下,如果D是一个空引用,则firstArgument在空引用上形成闭包。)
注解
该 Delegate 类是委托类型的基类。 但是,只有系统和编译器才能从类或Delegate类中显式MulticastDelegate派生。 不允许从委托类型派生新类型。 该 Delegate 类不被视为委托类型;它是用于派生委托类型的类。
大多数语言实现 delegate 关键字,并且这些语言的编译器能够派生自 MulticastDelegate 类;因此,用户应使用 delegate 语言提供的关键字。
注释
公共语言运行时为每个委托类型提供一种方法 Invoke ,其签名与委托相同。 无需从 C# 或Visual Basic显式调用此方法,因为编译器会自动调用此方法。 如果要查找委托类型的签名,此方法 Invoke 在 反射 中非常有用。
公共语言运行时提供每个委托类型和BeginInvokeEndInvoke方法,以启用委托的异步调用。 有关这些方法的详细信息,请参阅 异步调用同步方法。
委托类型的声明建立一个协定,该协定指定一个或多个方法的签名。 委托是具有引用的委托类型的实例:
- 类型实例方法和可分配给该类型的目标对象的实例方法。
- 类型的实例方法,在正式参数列表中公开隐藏
this参数。 该代表据说是公开的实例委托。 - 静态方法。
- 静态方法和可分配给方法的第一个参数的目标对象。 据说代表在第一次辩论中被关闭。
有关委托绑定的详细信息,请参阅 CreateDelegate(Type, Object, MethodInfo, Boolean) 方法重载。
当委托表示在其第一个参数(最常见的情况下)关闭的实例方法时,委托将存储对方法入口点的引用和对对象(称为目标)的引用,该对象的类型可分配给定义该方法的类型。 当委托表示打开的实例方法时,它将存储对方法入口点的引用。 委托签名必须在其正式参数列表中包括隐藏 this 参数;在这种情况下,委托没有对目标对象的引用,并且必须在调用委托时提供目标对象。
当委托表示静态方法时,委托存储对方法入口点的引用。 当委托表示在其第一个参数上关闭的静态方法时,委托将存储对方法入口点的引用,以及对可分配给方法的第一个参数类型的目标对象的引用。 调用委托时,静态方法的第一个参数将接收目标对象。 第一个参数必须是引用类型。
委托的调用列表是一组有序的委托,其中列表的每个元素都完全调用委托所表示的方法之一。 调用列表可以包含重复的方法。 在调用期间,按调用列表中显示的方法的顺序调用方法。 委托尝试在其调用列表中调用每个方法;每次在调用列表中出现重复项时,都会调用一次重复项。 委托是不可变的;创建后,委托的调用列表不会更改。
委托称为多播或可组合,因为委托可以调用一个或多个方法,并可用于组合操作。
合并操作(如 Combine 和 Remove)不会更改现有委托。 相反,此类操作返回一个新委托,其中包含操作的结果、未更改的委托或 null。 当操作的结果为不引用至少一个方法的委托时,组合操作将返回 null 。 当请求的操作不起作用时,组合操作将返回未更改的委托。
注释
托管语言使用 Combine 和 Remove 方法实现委托操作。 示例包括 Visual Basic 中的 AddHandler 和 RemoveHandler 语句以及 C# 中委托类型的 += 和 -= 运算符。
泛型委托类型可以具有变体类型参数。 逆变类型参数可用作委托的参数类型,协变类型参数可用作返回类型。 此功能允许从同一泛型类型定义构造的泛型委托类型(如果其类型参数是具有继承关系的引用类型),如 协变和逆变中所述,则它们与赋值兼容。
注释
由于方差而与分配兼容的泛型委托不一定是可组合的。 若要组合,类型必须完全匹配。 例如,假设命名 Derived 的类派生自名为 . Base. 可以将类型为 Action<Base> (Action(Of Base) in Visual Basic) 的委托分配给类型为 Action<Derived> 的变量,但无法组合这两个委托,因为类型不匹配。
如果调用的方法引发异常,该方法将停止执行,异常将传回委托的调用方,并且调用列表中的其余方法不会被调用。 捕获调用方中的异常不会更改此行为。
委托调用的方法的签名包括返回值时,委托将返回调用列表中最后一个元素的返回值。 当签名包含由引用传递的参数时,参数的最终值是调用列表中的每个方法按顺序执行并更新参数值的结果。
C 中委托最接近的等效项是函数指针。 委托可以表示静态方法或实例方法。 当委托表示实例方法时,委托不仅存储对方法入口点的引用,还存储对类实例的引用。 与函数指针不同,委托面向对象且类型安全。
CreateDelegate 示例
CreateDelegate 方法会创建指定类型的委托。
CreateDelegate(Type, MethodInfo) 方法
此方法重载等效于调用CreateDelegate(Type, MethodInfo, Boolean)的重载,并为true指定throwOnBindFailure。
构造函数
| 名称 | 说明 |
|---|---|
| Delegate(Object, String) |
初始化在指定类实例上调用指定实例方法的委托。 |
| Delegate(Type, String) |
初始化从指定类调用指定静态方法的委托。 |
属性
| 名称 | 说明 |
|---|---|
| HasSingleTarget |
获取一个值,该值指示是否 Delegate 具有单个调用目标。 |
| Method |
获取委托表示的方法。 |
| Target |
获取当前委托调用实例方法的类实例。 |
方法
运营商
| 名称 | 说明 |
|---|---|
| Equality(Delegate, Delegate) |
确定指定的委托是否相等。 |
| Inequality(Delegate, Delegate) |
确定指定的委托是否不相等。 |
扩展方法
| 名称 | 说明 |
|---|---|
| GetMethodInfo(Delegate) |
获取一个对象,该对象表示由指定委托表示的方法。 |