Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Anmärkning
Den här artikeln innehåller ytterligare kommentarer till referensdokumentationen för det här API:et.
DynamicMethod(String, Type, Type[], Boolean) konstruktor
Den dynamiska metod som skapas av den här konstruktorn är associerad med en anonym sammansättning i stället för en befintlig typ eller modul. Den anonyma sammansättningen finns bara för att tillhandahålla en sandbox-miljö för dynamiska metoder, dvs. för att isolera dem från annan kod. Den här miljön gör det säkert för den dynamiska metoden att genereras och köras av delvis betrodd kod.
Anonymt värdbaserade dynamiska metoder har inte automatisk åtkomst till några typer eller medlemmar som är private, protectedeller internal (Friend i Visual Basic). Detta skiljer sig från dynamiska metoder som är associerade med en befintlig typ eller modul, som har åtkomst till dolda medlemmar i deras associerade omfång.
Ange true för restrictedSkipVisibility om din dynamiska metod måste komma åt typer eller medlemmar som är private, protectedeller internal. Detta ger den dynamiska metoden begränsad åtkomst till dessa medlemmar. Det vill: medlemmarna kan endast nås om följande villkor uppfylls:
Målmedlemmarna tillhör en sammansättning som har en förtroendenivå som är lika med eller lägre än den anropsstack som genererar den dynamiska metoden.
Anropsstacken som genererar den dynamiska metoden beviljas ReflectionPermission med flaggan ReflectionPermissionFlag.RestrictedMemberAccess. Detta är alltid sant när koden körs med fullständigt förtroende. För delvis betrodd kod är det bara sant om värden uttryckligen beviljar behörighetsrätten.
Viktigt!
Om behörigheten inte har beviljats utlöses ett säkerhetsfel när CreateDelegate anropas eller när den dynamiska metoden anropas, inte när konstruktorn anropas. Inga särskilda behörigheter krävs för att generera den dynamiska metoden.
En dynamisk metod som skapas med restrictedSkipVisibility inställd på true kan till exempel komma åt en privat medlem av vilken assembly som helst i anropsstacken, om anropsstacken har beviljats begränsad åtkomst till medlemmar. Om den dynamiska metoden skapas med delvis betrodd kod i anropsstacken kan den inte komma åt en privat medlem av en typ i en .NET Framework-sammansättning, eftersom sådana sammansättningar är fullständigt betrodda.
Om restrictedSkipVisibility är falsetillämpas JIT-synlighetskontroller. Koden i den dynamiska metoden har åtkomst till offentliga metoder för offentliga klasser och undantag utlöses om den försöker komma åt typer eller medlemmar som är private, protectedeller internal.
När en anonymt värdbaserad dynamisk metod skapas inkluderas anropsstacken för den utsändande sammansättningen. När metoden anropas används behörigheterna för den sändande anropsstacken i stället för den faktiska anroparens behörigheter. Den dynamiska metoden kan därför inte köras på en högre behörighetsnivå än den sammansättning som skickade den, även om den skickas till och körs av en sammansättning som har en högre förtroendenivå.
Den här konstruktorn anger metodattributen MethodAttributes.Public och MethodAttributes.Static, och anropskonventionen CallingConventions.Standard.
Anmärkning
Den här konstruktorn introducerades i .NET Framework 3.5 eller senare.
DynamicMethod(String, Type, Type[], Module) konstruktor
Den här konstruktorn anger metodattribut MethodAttributes.Public och MethodAttributes.Static, anropar konvention CallingConventions.Standardoch hoppar inte över jit-synlighetskontroller (just-in-time).
Den dynamiska metoden som skapas med den här konstruktorn har åtkomst till offentliga och internal (Friend i Visual Basic) medlemmar av alla typer som ingår i modulen m.
Anmärkning
För bakåtkompatibilitet kräver den här konstruktorn SecurityPermission med SecurityPermissionFlag.ControlEvidence-flagga om båda följande villkor är uppfyllda: m är en annan modul än den modul som anropar, och kravet på ReflectionPermission med ReflectionPermissionFlag.MemberAccess-flagga har misslyckats. Om efterfrågan på SecurityPermission blir framgångsrik tillåts operationen.
Exempel
I följande kodexempel skapas en dynamisk metod som tar två parametrar. Exemplet genererar en enkel funktionstext som skriver ut den första parametern till konsolen, och i exemplet används den andra parametern som returvärde för metoden. Exemplet slutför metoden genom att skapa ett ombud, anropar ombudet med olika parametrar och anropar slutligen den dynamiska metoden med hjälp av Invoke(Object, BindingFlags, Binder, Object[], CultureInfo) metoden.
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) konstruktor
Den dynamiska metoden som skapas med den här konstruktorn har åtkomst till alla medlemmar av typen owner, och till offentliga och internal (Friend i Visual Basic) medlemmar av alla andra typer i modulen som innehåller owner.
Den här konstruktorn anger metodattribut MethodAttributes.Public och MethodAttributes.Static, anropar konvention CallingConventions.Standardoch hoppar inte över jit-synlighetskontroller (just-in-time).
Anmärkning
För bakåtkompatibilitet kräver denna konstruktor SecurityPermission med flaggan SecurityPermissionFlag.ControlEvidence om följande villkor är uppfyllda: owner finns i en annan modul än den som anropar och kravet på ReflectionPermission med flaggan ReflectionPermissionFlag.MemberAccess har misslyckats. Om efterfrågan på SecurityPermission blir framgångsrik tillåts operationen.
Exempel
I följande kodexempel skapas en DynamicMethod som är logiskt associerad med en typ. Den här associationen ger den åtkomst till de privata medlemmarna av den typen.
Kodexemplet definierar en klass med namnet Example med ett privat fält, en klass med namnet DerivedFromExample som härleds från den första klassen, en ombudstyp med namnet UseLikeStatic som returnerar Int32 och har parametrar av typen Example och Int32, och en ombudstyp med namnet UseLikeInstance som returnerar Int32 och har en parameter av typen Int32.
Exempelkoden skapar sedan en DynamicMethod som ändrar det privata fältet för en instans av Example och returnerar det tidigare värdet.
Anmärkning
I allmänhet är det inte bra objektorienterad kodning att ändra de interna fälten i klasser.
Exempelkoden skapar en instans av Example och skapar sedan två ombud. Den första är av typen UseLikeStatic, som har samma parametrar som den dynamiska metoden. Den andra är av typen UseLikeInstance, som saknar den första parametern (av typen Example). Den här delegeringen skapas med hjälp av metodöverlagringen CreateDelegate(Type, Object); den andra parametern för den metodöverlagringen är en instans av Example, i det här fallet den instans som just har skapats, som är bunden till den nyligen skapade delegeringen. När den delegerade anropas agerar den dynamiska metoden på den bundna instansen av Example.
Anmärkning
Det här är ett exempel på de avslappnade reglerna för delegatbindning som introducerades i .NET Framework 2.0, tillsammans med nya överlagringar av Delegate.CreateDelegate metoden. Mer information finns i Delegate klassen .
Delegeringen UseLikeStatic anropas genom att skicka in den instans av Example som är bunden till delegeringen UseLikeInstance. Sedan anropas delegeraren UseLikeInstance så att båda delegerarna agerar på samma instans av Example. Ändringarna i värdena för det interna fältet visas efter varje anrop. Slutligen är en UseLikeInstance delegat bunden till en instans av DerivedFromExample, och delegatanropen upprepas.
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'