System.Reflection.Emit.DynamicMethod 构造函数

注释

本文提供了此 API 参考文档的补充说明。

DynamicMethod(String, Type, Type[], Boolean) 构造函数

此构造函数创建的动态方法与匿名程序集(而不是现有类型或模块)相关联。 匿名程序集仅用于为动态方法提供沙盒环境,即将它们与其他代码隔离开来。 此环境使动态方法可以安全地由部分受信任的代码发出和执行。

匿名托管的动态方法无权自动访问任何类型或成员 privateprotected或者 internalFriend 在 Visual Basic 中)。 这不同于与现有类型或模块关联的动态方法,这些方法有权访问其关联范围内的隐藏成员。

指定true以用于restrictedSkipVisibility,如果您的动态方法必须访问privateprotectedinternal的类型或成员。 这样,动态方法将限制对这些成员的访问权限。 也就是说,仅当满足以下条件时,才能访问成员:

  • 目标成员属于一个程序集,其信任级别等于或低于发出动态方法的调用堆栈。

  • 发出动态方法的调用堆栈被授予带有ReflectionPermission标志的ReflectionPermissionFlag.RestrictedMemberAccess。 当代码以完全信任执行时,始终如此。 对于部分受信任的代码,仅当主机显式授予权限时才为 true。

    重要

    如果未授予权限,则在调用 CreateDelegate 或调用动态方法时抛出安全异常,而不是在调用此构造函数时抛出。 发出动态方法不需要任何特殊权限。

例如,如果调用堆栈被授予受限成员访问权限,则创建的 restrictedSkipVisibility 动态方法设置为 true 可以访问调用堆栈上任何程序集的私有成员。 如果动态方法是在调用堆栈上使用部分受信任的代码创建的,则它无法访问 .NET Framework 程序集中类型的私有成员,因为此类程序集完全受信任。

restrictedSkipVisibilityfalse时,强制执行 JIT 可见性检查。 动态方法中的代码可以访问公共类中的公共方法,如果尝试访问类型或成员属于privateprotectedinternal,则会引发异常。

构造匿名托管的动态方法时,将包含发出程序集的调用堆栈。 调用该方法时,将使用发出调用堆栈的权限,而不是实际调用方的权限。 因此,动态方法的特权级别不能高于发出它的程序集的特权级别,即使它被传递给具有较高信任级别的程序集并由其执行。

此构造函数指定方法属性 MethodAttributes.PublicMethodAttributes.Static调用约定 CallingConventions.Standard

注释

此构造函数是在 .NET Framework 3.5 或更高版本中引入的。

DynamicMethod(String, Type, Type[], Module) 构造函数

此构造函数指定了方法属性 MethodAttributes.PublicMethodAttributes.Static,调用约定 CallingConventions.Standard,并且不会跳过即时 (JIT) 可见性检查。

使用此构造函数创建的动态方法可以访问模块internal中包含的所有类型的公共成员和Friend成员(在 Visual Basic 中为m)。

注释

为了向后兼容,如果以下条件均为 true,则此构造函数要求SecurityPermission使用SecurityPermissionFlag.ControlEvidence标志:m是一个非调用模块的模块,并且对使用ReflectionPermission标志的ReflectionPermissionFlag.MemberAccess的需求未能成功。 如果对 SecurityPermission 的请求成功,则允许进行操作。

例子

下面的代码示例创建一个采用两个参数的动态方法。 该示例发出一个简单的函数正文,它将第一个参数输出到控制台,该示例使用第二个参数作为方法的返回值。 该示例通过创建委托,使用不同参数调用委托,最后通过 Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) 方法来调用动态方法,从而完成整个过程。

using System;
using System.Reflection;
using System.Reflection.Emit;

public class Test
{
    // Declare a delegate that will be used to execute the completed
    // dynamic method.
    private delegate int HelloInvoker(string msg, int ret);

    public static void Main()
    {
        // Create an array that specifies the types of the parameters
        // of the dynamic method. This method has a string parameter
        // and an int parameter.
        Type[] helloArgs = {typeof(string), typeof(int)};

        // Create a dynamic method with the name "Hello", a return type
        // of int, and two parameters whose types are specified by the
        // array helloArgs. Create the method in the module that
        // defines the Test class.
        DynamicMethod hello = new DynamicMethod("Hello",
            typeof(int),
            helloArgs,
            typeof(Test).Module);

        // Create an array that specifies the parameter types of the
        // overload of Console.WriteLine to be used in Hello.
        Type[] writeStringArgs = {typeof(string)};
        // Get the overload of Console.WriteLine that has one
        // String parameter.
        MethodInfo writeString =
            typeof(Console).GetMethod("WriteLine", writeStringArgs);

        // Get an ILGenerator and emit a body for the dynamic method.
        ILGenerator il = hello.GetILGenerator();
        // Load the first argument, which is a string, onto the stack.
        il.Emit(OpCodes.Ldarg_0);
        // Call the overload of Console.WriteLine that prints a string.
        il.EmitCall(OpCodes.Call, writeString, null);
        // The Hello method returns the value of the second argument;
        // to do this, load the second argument onto the stack and return.
        il.Emit(OpCodes.Ldarg_1);
        il.Emit(OpCodes.Ret);

        // Create a delegate that represents the dynamic method. This
        // action completes the method. Further attempts to change the
        // method are ignored and no exception is thrown.
        HelloInvoker hi =
            (HelloInvoker) hello.CreateDelegate(typeof(HelloInvoker));

        // Use the delegate to execute the dynamic method. Save and
        // print the return value.
        int retval = hi("\r\nHello, World!", 42);
        Console.WriteLine("Executing delegate hi(\"Hello, World!\", 42) returned {0}",
            retval);

        // Do it again, with different arguments.
        retval = hi("\r\nHi, Mom!", 5280);
        Console.WriteLine("Executing delegate hi(\"Hi, Mom!\", 5280) returned {0}",
            retval);

        // Create an array of arguments to use with the Invoke method.
        object[] invokeArgs = {"\r\nHello, World!", 42};
        // Invoke the dynamic method using the arguments. This is much
        // slower than using the delegate, because you must create an
        // array to contain the arguments, and ValueType arguments
        // must be boxed.
        object objRet = hello.Invoke(null, invokeArgs);
        Console.WriteLine("hello.Invoke returned {0}", objRet);
    }
}
Imports System.Reflection
Imports System.Reflection.Emit

Public Class Test
    ' Declare a delegate that will be used to execute the completed
    ' dynamic method. 
    Private Delegate Function HelloInvoker(ByVal msg As String, _
        ByVal ret As Integer) As Integer

    Public Shared Sub Main()
        ' Create an array that specifies the types of the parameters
        ' of the dynamic method. This method has a String parameter
        ' and an Integer parameter.
        Dim helloArgs() As Type = {GetType(String), GetType(Integer)}

        ' Create a dynamic method with the name "Hello", a return type
        ' of Integer, and two parameters whose types are specified by
        ' the array helloArgs. Create the method in the module that
        ' defines the Test class.
        Dim hello As New DynamicMethod("Hello", _
            GetType(Integer), _
            helloArgs, _
            GetType(Test).Module)

        ' Create an array that specifies the parameter types of the
        ' overload of Console.WriteLine to be used in Hello.
        Dim writeStringArgs() As Type = {GetType(String)}
        ' Get the overload of Console.WriteLine that has one
        ' String parameter.
        Dim writeString As MethodInfo = GetType(Console). _
            GetMethod("WriteLine", writeStringArgs) 

        ' Get an ILGenerator and emit a body for the dynamic method.
        Dim il As ILGenerator = hello.GetILGenerator()
        ' Load the first argument, which is a string, onto the stack.
        il.Emit(OpCodes.Ldarg_0)
        ' Call the overload of Console.WriteLine that prints a string.
        il.EmitCall(OpCodes.Call, writeString, Nothing)
        ' The Hello method returns the value of the second argument;
        ' to do this, load the second argument onto the stack and return.
        il.Emit(OpCodes.Ldarg_1)
        il.Emit(OpCodes.Ret)

        ' Create a delegate that represents the dynamic method. This
        ' action completes the method, and any further attempts to
        ' change the method are ignored and don't throw an exception.
    Dim hi As HelloInvoker = _
            hello.CreateDelegate(GetType(HelloInvoker))

        ' Use the delegate to execute the dynamic method. Save and
        ' print the return value.
        Dim retval As Integer = hi(vbCrLf & "Hello, World!", 42)
        Console.WriteLine("Executing delegate hi(""Hello, World!"", 42) returned " _
            & retval)

        ' Do it again, with different arguments.
        retval = hi(vbCrLf & "Hi, Mom!", 5280)
        Console.WriteLine("Executing delegate hi(""Hi, Mom!"", 5280) returned " _
            & retval)

        ' Create an array of arguments to use with the Invoke method.
        Dim invokeArgs() As Object = {vbCrLf & "Hello, World!", 42}
        ' Invoke the dynamic method using the arguments. This is much
        ' slower than using the delegate, because you must create an
        ' array to contain the arguments, and ValueType arguments
        ' must be boxed. Note that this overload of Invoke is 
        ' inherited from MethodBase, and simply calls the more 
        ' complete overload of Invoke.
        Dim objRet As Object = hello.Invoke(Nothing, invokeArgs)
        Console.WriteLine("hello.Invoke returned " & objRet)
    End Sub
End Class

' This code example produces the following output:
'
'Hello, World!
'Executing delegate hi("Hello, World!", 42) returned 42
'
'Hi, Mom!
'Executing delegate hi("Hi, Mom!", 5280) returned 5280
'
'Hello, World!
'hello.Invoke returned 42
'

DynamicMethod(String, Type, Type[], Type) 构造函数

使用此构造函数创建的动态方法可以访问类型owner的所有成员,以及包含internal的模块中所有其他类型的公共成员和Friend(在 Visual Basic 中为owner)成员。

此构造函数指定了方法属性 MethodAttributes.PublicMethodAttributes.Static,调用约定 CallingConventions.Standard,并且不会跳过即时 (JIT) 可见性检查。

注释

为了向后兼容,如果以下条件均为 true,则此构造函数要求SecurityPermissionSecurityPermissionFlag.ControlEvidence标志一起使用:owner在调用模块以外的模块中,并且对ReflectionPermission的需求与ReflectionPermissionFlag.MemberAccess标志一起使用时已失败。 如果对 SecurityPermission 的请求成功,则允许进行操作。

例子

下面的代码示例创建一个与某一类型在逻辑上关联的 DynamicMethod。 此关联允许该对象访问该类型的私有成员。

该代码示例定义了一个具有私有字段的Example类、一个名为派生自第一类的类DerivedFromExample、一个返回UseLikeStaticInt32类型并具有类型ExampleInt32参数的委托类型,以及一个名为返回UseLikeInstance的委托类型,以及一个类型Int32为类型的Int32委托类型。

然后,示例代码创建一个 DynamicMethod 更改实例 Example 的私有字段并返回上一个值。

注释

一般情况下,更改类的内部字段并不适合面向对象的编码实践。

示例代码创建一个实例 Example ,然后创建两个委托。 第一个是类型UseLikeStatic,其参数与动态方法相同。 第二种类型, UseLikeInstance缺少第一个参数(类型 Example)。 此委托是使用 CreateDelegate(Type, Object) 方法的重载版本创建的,该方法的重载版本的第二个参数是刚刚创建的 Example 实例,并且该实例绑定到新创建的委托。 每当调用该委托时,动态方法将作用于绑定实例。Example

注释

这是在 .NET Framework 2.0 中引入的宽松的委托绑定规则示例,以及 Delegate.CreateDelegate 方法的新重载。 有关更多信息,请参见 Delegate 类。

UseLikeStatic委托被调用,并传入绑定到Example委托的UseLikeInstance实例。 UseLikeInstance委托被调用,然后使两个委托对同一实例Example执行操作。 每次调用后,都会显示内部字段值的变化。 最后, UseLikeInstance 委托绑定到一个实例 DerivedFromExample,并重复委托调用。

using System;
using System.Reflection;
using System.Reflection.Emit;

// These classes are for demonstration purposes.
//
public class Example
{
    private int id = 0;
    public Example(int id)
    {
        this.id = id;
    }
    public int ID { get { return id; }}
}

public class DerivedFromExample : Example
{
    public DerivedFromExample(int id) : base(id) {}
}

// Two delegates are declared: UseLikeInstance treats the dynamic
// method as if it were an instance method, and UseLikeStatic
// treats the dynamic method in the ordinary fashion.
//
public delegate int UseLikeInstance(int newID);
public delegate int UseLikeStatic(Example ex, int newID);

public class Demo
{
    public static void Main()
    {
        // This dynamic method changes the private id field. It has
        // no name; it returns the old id value (return type int);
        // it takes two parameters, an instance of Example and
        // an int that is the new value of id; and it is declared
        // with Example as the owner type, so it can access all
        // members, public and private.
        //
        DynamicMethod changeID = new DynamicMethod(
            "",
            typeof(int),
            new Type[] { typeof(Example), typeof(int) },
            typeof(Example)
        );

        // Get a FieldInfo for the private field 'id'.
        FieldInfo fid = typeof(Example).GetField(
            "id",
            BindingFlags.NonPublic | BindingFlags.Instance
        );

        ILGenerator ilg = changeID.GetILGenerator();

        // Push the current value of the id field onto the
        // evaluation stack. It's an instance field, so load the
        // instance of Example before accessing the field.
        ilg.Emit(OpCodes.Ldarg_0);
        ilg.Emit(OpCodes.Ldfld, fid);

        // Load the instance of Example again, load the new value
        // of id, and store the new field value.
        ilg.Emit(OpCodes.Ldarg_0);
        ilg.Emit(OpCodes.Ldarg_1);
        ilg.Emit(OpCodes.Stfld, fid);

        // The original value of the id field is now the only
        // thing on the stack, so return from the call.
        ilg.Emit(OpCodes.Ret);

        // Create a delegate that uses changeID in the ordinary
        // way, as a static method that takes an instance of
        // Example and an int.
        //
        UseLikeStatic uls =
            (UseLikeStatic) changeID.CreateDelegate(
                typeof(UseLikeStatic)
            );

        // Create an instance of Example with an id of 42.
        //
        Example ex = new Example(42);

        // Create a delegate that is bound to the instance of
        // of Example. This is possible because the first
        // parameter of changeID is of type Example. The
        // delegate has all the parameters of changeID except
        // the first.
        UseLikeInstance uli =
            (UseLikeInstance) changeID.CreateDelegate(
                typeof(UseLikeInstance),
                ex
            );

        // First, change the value of id by calling changeID as
        // a static method, passing in the instance of Example.
        //
        Console.WriteLine(
            "Change the value of id; previous value: {0}",
            uls(ex, 1492)
        );

        // Change the value of id again using the delegate bound
        // to the instance of Example.
        //
        Console.WriteLine(
            "Change the value of id; previous value: {0}",
            uli(2700)
        );

        Console.WriteLine("Final value of id: {0}", ex.ID);

        // Now repeat the process with a class that derives
        // from Example.
        //
        DerivedFromExample dfex = new DerivedFromExample(71);

        uli = (UseLikeInstance) changeID.CreateDelegate(
                typeof(UseLikeInstance),
                dfex
            );

        Console.WriteLine(
            "Change the value of id; previous value: {0}",
            uls(dfex, 73)
        );
        Console.WriteLine(
            "Change the value of id; previous value: {0}",
            uli(79)
        );
        Console.WriteLine("Final value of id: {0}", dfex.ID);
    }
}

/* This code example produces the following output:

Change the value of id; previous value: 42
Change the value of id; previous value: 1492
Final value of id: 2700
Change the value of id; previous value: 71
Change the value of id; previous value: 73
Final value of id: 79
 */
Imports System.Reflection
Imports System.Reflection.Emit

' These classes are for demonstration purposes.
'
Public Class Example
    Private _id As Integer = 0
    
    Public Sub New(ByVal newId As Integer) 
        _id = newId    
    End Sub
    
    Public ReadOnly Property ID() As Integer 
        Get
            Return _id
        End Get
    End Property 
End Class

Public Class DerivedFromExample
    Inherits Example
    
    Public Sub New(ByVal newId As Integer) 
        MyBase.New(newId)
    End Sub
End Class
 
' Two delegates are declared: UseLikeInstance treats the dynamic
' method as if it were an instance method, and UseLikeStatic
' treats the dynamic method in the ordinary fashion.
' 
Public Delegate Function UseLikeInstance(ByVal newID As Integer) _
    As Integer 
Public Delegate Function UseLikeStatic(ByVal ex As Example, _
    ByVal newID As Integer) As Integer 

Public Class Demo
    
    Public Shared Sub Main() 
        ' This dynamic method changes the private _id field. It 
        ' has no name; it returns the old _id value (return type 
        ' Integer); it takes two parameters, an instance of Example 
        ' and an Integer that is the new value of _id; and it is 
        ' declared with Example as the owner type, so it can 
        ' access all members, public and private.
        '
        Dim changeID As New DynamicMethod( _
            "", _
            GetType(Integer), _
            New Type() {GetType(Example), GetType(Integer)}, _
            GetType(Example) _
        )
        
        ' Get a FieldInfo for the private field '_id'.
        Dim fid As FieldInfo = GetType(Example).GetField( _
            "_id", _
            BindingFlags.NonPublic Or BindingFlags.Instance _
        )
        
        Dim ilg As ILGenerator = changeID.GetILGenerator()
        
        ' Push the current value of the id field onto the 
        ' evaluation stack. It's an instance field, so load the
        ' instance of Example before accessing the field.
        ilg.Emit(OpCodes.Ldarg_0)
        ilg.Emit(OpCodes.Ldfld, fid)
        
        ' Load the instance of Example again, load the new value 
        ' of id, and store the new field value. 
        ilg.Emit(OpCodes.Ldarg_0)
        ilg.Emit(OpCodes.Ldarg_1)
        ilg.Emit(OpCodes.Stfld, fid)
        
        ' The original value of the id field is now the only 
        ' thing on the stack, so return from the call.
        ilg.Emit(OpCodes.Ret)
        
        
        ' Create a delegate that uses changeID in the ordinary
        ' way, as a static method that takes an instance of
        ' Example and an Integer.
        '
        Dim uls As UseLikeStatic = CType( _
            changeID.CreateDelegate(GetType(UseLikeStatic)), _
            UseLikeStatic _
        )
        
        ' Create an instance of Example with an id of 42.
        '
        Dim ex As New Example(42)
        
        ' Create a delegate that is bound to the instance of 
        ' of Example. This is possible because the first 
        ' parameter of changeID is of type Example. The 
        ' delegate has all the parameters of changeID except
        ' the first.
        Dim uli As UseLikeInstance = CType( _
            changeID.CreateDelegate( _
                GetType(UseLikeInstance), _
                ex), _
            UseLikeInstance _
        )
        
        ' First, change the value of _id by calling changeID as
        ' a static method, passing in the instance of Example.
        '
        Console.WriteLine( _
            "Change the value of _id; previous value: {0}", _
            uls(ex, 1492) _
        )
        
        ' Change the value of _id again using the delegate 
        ' bound to the instance of Example.
        '
        Console.WriteLine( _
            "Change the value of _id; previous value: {0}", _
            uli(2700) _
        )
        
        Console.WriteLine("Final value of _id: {0}", ex.ID)
    

        ' Now repeat the process with a class that derives
        ' from Example.
        '
        Dim dfex As New DerivedFromExample(71)

        uli = CType( _
            changeID.CreateDelegate( _
                GetType(UseLikeInstance), _
                dfex), _
            UseLikeInstance _
        )

        Console.WriteLine( _
            "Change the value of _id; previous value: {0}", _
            uls(dfex, 73) _
        )
        Console.WriteLine( _
            "Change the value of _id; previous value: {0}", _
            uli(79) _
        )
        Console.WriteLine("Final value of _id: {0}", dfex.ID)

    End Sub
End Class

' This code example produces the following output:
'
'Change the value of _id; previous value: 42
'Change the value of _id; previous value: 1492
'Final value of _id: 2700
'Change the value of _id; previous value: 71
'Change the value of _id; previous value: 73
'Final value of _id: 79'