TypeBuilder 类
定义
重要
一些信息与预发行产品相关,相应产品在发行之前可能会进行重大修改。 对于此处提供的信息,Microsoft 不作任何明示或暗示的担保。
定义并创建运行时类的新实例。
public ref class TypeBuilder abstract : System::Reflection::TypeInfo
public ref class TypeBuilder sealed : Type
public ref class TypeBuilder sealed : System::Reflection::TypeInfo
public ref class TypeBuilder sealed : Type, System::Runtime::InteropServices::_TypeBuilder
public ref class TypeBuilder sealed : System::Reflection::TypeInfo, System::Runtime::InteropServices::_TypeBuilder
public abstract class TypeBuilder : System.Reflection.TypeInfo
public sealed class TypeBuilder : Type
public sealed class TypeBuilder : System.Reflection.TypeInfo
[System.Runtime.InteropServices.ClassInterface(System.Runtime.InteropServices.ClassInterfaceType.None)]
public sealed class TypeBuilder : Type, System.Runtime.InteropServices._TypeBuilder
[System.Runtime.InteropServices.ClassInterface(System.Runtime.InteropServices.ClassInterfaceType.None)]
[System.Runtime.InteropServices.ComVisible(true)]
public sealed class TypeBuilder : Type, System.Runtime.InteropServices._TypeBuilder
[System.Runtime.InteropServices.ClassInterface(System.Runtime.InteropServices.ClassInterfaceType.None)]
[System.Runtime.InteropServices.ComVisible(true)]
public sealed class TypeBuilder : System.Reflection.TypeInfo, System.Runtime.InteropServices._TypeBuilder
type TypeBuilder = class
inherit TypeInfo
type TypeBuilder = class
inherit Type
[<System.Runtime.InteropServices.ClassInterface(System.Runtime.InteropServices.ClassInterfaceType.None)>]
type TypeBuilder = class
inherit Type
interface _TypeBuilder
[<System.Runtime.InteropServices.ClassInterface(System.Runtime.InteropServices.ClassInterfaceType.None)>]
[<System.Runtime.InteropServices.ComVisible(true)>]
type TypeBuilder = class
inherit Type
interface _TypeBuilder
[<System.Runtime.InteropServices.ClassInterface(System.Runtime.InteropServices.ClassInterfaceType.None)>]
[<System.Runtime.InteropServices.ComVisible(true)>]
type TypeBuilder = class
inherit TypeInfo
interface _TypeBuilder
Public MustInherit Class TypeBuilder
Inherits TypeInfo
Public NotInheritable Class TypeBuilder
Inherits Type
Public NotInheritable Class TypeBuilder
Inherits TypeInfo
Public NotInheritable Class TypeBuilder
Inherits Type
Implements _TypeBuilder
Public NotInheritable Class TypeBuilder
Inherits TypeInfo
Implements _TypeBuilder
- 继承
- 继承
- 继承
- 属性
- 实现
示例
下面的代码示例演示如何定义和使用动态程序集。 示例程序集包含一种类型, MyDynamicType该类型具有专用字段、获取和设置专用字段的属性、初始化专用字段的构造函数,以及一个方法,该方法将用户提供的数字乘以专用字段值并返回结果。
using System;
using System.Reflection;
using System.Reflection.Emit;
class DemoAssemblyBuilder
{
public static void Main()
{
// This code creates an assembly that contains one type,
// named "MyDynamicType", that has a private field, a property
// that gets and sets the private field, constructors that
// initialize the private field, and a method that multiplies
// a user-supplied number by the private field value and returns
// the result. In C# the type might look like this:
/*
public class MyDynamicType
{
private int m_number;
public MyDynamicType() : this(42) {}
public MyDynamicType(int initNumber)
{
m_number = initNumber;
}
public int Number
{
get { return m_number; }
set { m_number = value; }
}
public int MyMethod(int multiplier)
{
return m_number * multiplier;
}
}
*/
var aName = new AssemblyName("DynamicAssemblyExample");
AssemblyBuilder ab =
AssemblyBuilder.DefineDynamicAssembly(
aName,
AssemblyBuilderAccess.Run);
// The module name is usually the same as the assembly name.
ModuleBuilder mb = ab.DefineDynamicModule(aName.Name ?? "DynamicAssemblyExample");
TypeBuilder tb = mb.DefineType(
"MyDynamicType",
TypeAttributes.Public);
// Add a private field of type int (Int32).
FieldBuilder fbNumber = tb.DefineField(
"m_number",
typeof(int),
FieldAttributes.Private);
// Define a constructor that takes an integer argument and
// stores it in the private field.
Type[] parameterTypes = { typeof(int) };
ConstructorBuilder ctor1 = tb.DefineConstructor(
MethodAttributes.Public,
CallingConventions.Standard,
parameterTypes);
ILGenerator ctor1IL = ctor1.GetILGenerator();
// For a constructor, argument zero is a reference to the new
// instance. Push it on the stack before calling the base
// class constructor. Specify the default constructor of the
// base class (System.Object) by passing an empty array of
// types (Type.EmptyTypes) to GetConstructor.
ctor1IL.Emit(OpCodes.Ldarg_0);
ConstructorInfo? ci = typeof(object).GetConstructor(Type.EmptyTypes);
ctor1IL.Emit(OpCodes.Call, ci!);
// Push the instance on the stack before pushing the argument
// that is to be assigned to the private field m_number.
ctor1IL.Emit(OpCodes.Ldarg_0);
ctor1IL.Emit(OpCodes.Ldarg_1);
ctor1IL.Emit(OpCodes.Stfld, fbNumber);
ctor1IL.Emit(OpCodes.Ret);
// Define a default constructor that supplies a default value
// for the private field. For parameter types, pass the empty
// array of types or pass null.
ConstructorBuilder ctor0 = tb.DefineConstructor(
MethodAttributes.Public,
CallingConventions.Standard,
Type.EmptyTypes);
ILGenerator ctor0IL = ctor0.GetILGenerator();
// For a constructor, argument zero is a reference to the new
// instance. Push it on the stack before pushing the default
// value on the stack, then call constructor ctor1.
ctor0IL.Emit(OpCodes.Ldarg_0);
ctor0IL.Emit(OpCodes.Ldc_I4_S, 42);
ctor0IL.Emit(OpCodes.Call, ctor1);
ctor0IL.Emit(OpCodes.Ret);
// Define a property named Number that gets and sets the private
// field.
//
// The last argument of DefineProperty is null, because the
// property has no parameters. (If you don't specify null, you must
// specify an array of Type objects. For a parameterless property,
// use the built-in array with no elements: Type.EmptyTypes)
PropertyBuilder pbNumber = tb.DefineProperty(
"Number",
PropertyAttributes.HasDefault,
typeof(int),
null);
// The property "set" and property "get" methods require a special
// set of attributes.
MethodAttributes getSetAttr = MethodAttributes.Public |
MethodAttributes.SpecialName | MethodAttributes.HideBySig;
// Define the "get" accessor method for Number. The method returns
// an integer and has no arguments. (Note that null could be
// used instead of Types.EmptyTypes)
MethodBuilder mbNumberGetAccessor = tb.DefineMethod(
"get_Number",
getSetAttr,
typeof(int),
Type.EmptyTypes);
ILGenerator numberGetIL = mbNumberGetAccessor.GetILGenerator();
// For an instance property, argument zero is the instance. Load the
// instance, then load the private field and return, leaving the
// field value on the stack.
numberGetIL.Emit(OpCodes.Ldarg_0);
numberGetIL.Emit(OpCodes.Ldfld, fbNumber);
numberGetIL.Emit(OpCodes.Ret);
// Define the "set" accessor method for Number, which has no return
// type and takes one argument of type int (Int32).
MethodBuilder mbNumberSetAccessor = tb.DefineMethod(
"set_Number",
getSetAttr,
null,
new Type[] { typeof(int) });
ILGenerator numberSetIL = mbNumberSetAccessor.GetILGenerator();
// Load the instance and then the numeric argument, then store the
// argument in the field.
numberSetIL.Emit(OpCodes.Ldarg_0);
numberSetIL.Emit(OpCodes.Ldarg_1);
numberSetIL.Emit(OpCodes.Stfld, fbNumber);
numberSetIL.Emit(OpCodes.Ret);
// Last, map the "get" and "set" accessor methods to the
// PropertyBuilder. The property is now complete.
pbNumber.SetGetMethod(mbNumberGetAccessor);
pbNumber.SetSetMethod(mbNumberSetAccessor);
// Define a method that accepts an integer argument and returns
// the product of that integer and the private field m_number. This
// time, the array of parameter types is created on the fly.
MethodBuilder meth = tb.DefineMethod(
"MyMethod",
MethodAttributes.Public,
typeof(int),
new Type[] { typeof(int) });
ILGenerator methIL = meth.GetILGenerator();
// To retrieve the private instance field, load the instance it
// belongs to (argument zero). After loading the field, load the
// argument one and then multiply. Return from the method with
// the return value (the product of the two numbers) on the
// execution stack.
methIL.Emit(OpCodes.Ldarg_0);
methIL.Emit(OpCodes.Ldfld, fbNumber);
methIL.Emit(OpCodes.Ldarg_1);
methIL.Emit(OpCodes.Mul);
methIL.Emit(OpCodes.Ret);
// Finish the type.
Type? t = tb.CreateType();
// Because AssemblyBuilderAccess includes Run, the code can be
// executed immediately. Start by getting reflection objects for
// the method and the property.
MethodInfo? mi = t?.GetMethod("MyMethod");
PropertyInfo? pi = t?.GetProperty("Number");
// Create an instance of MyDynamicType using the default
// constructor.
object? o1 = null;
if (t is not null)
o1 = Activator.CreateInstance(t);
// Display the value of the property, then change it to 127 and
// display it again. Use null to indicate that the property
// has no index.
Console.WriteLine("o1.Number: {0}", pi?.GetValue(o1, null));
pi?.SetValue(o1, 127, null);
Console.WriteLine("o1.Number: {0}", pi?.GetValue(o1, null));
// Call MyMethod, passing 22, and display the return value, 22
// times 127. Arguments must be passed as an array, even when
// there is only one.
object[] arguments = { 22 };
Console.WriteLine("o1.MyMethod(22): {0}",
mi?.Invoke(o1, arguments));
// Create an instance of MyDynamicType using the constructor
// that specifies m_Number. The constructor is identified by
// matching the types in the argument array. In this case,
// the argument array is created on the fly. Display the
// property value.
object? o2 = null;
if (t is not null)
o2 = Activator.CreateInstance(t, new object[] { 5280 });
Console.WriteLine("o2.Number: {0}", pi?.GetValue(o2, null));
}
}
/* This code produces the following output:
o1.Number: 42
o1.Number: 127
o1.MyMethod(22): 2794
o2.Number: 5280
*/
Imports System.Reflection
Imports System.Reflection.Emit
Class DemoAssemblyBuilder
Public Shared Sub Main()
' This code creates an assembly that contains one type,
' named "MyDynamicType", that has a private field, a property
' that gets and sets the private field, constructors that
' initialize the private field, and a method that multiplies
' a user-supplied number by the private field value and returns
' the result. The code might look like this in Visual Basic:
'
'Public Class MyDynamicType
' Private m_number As Integer
'
' Public Sub New()
' Me.New(42)
' End Sub
'
' Public Sub New(ByVal initNumber As Integer)
' m_number = initNumber
' End Sub
'
' Public Property Number As Integer
' Get
' Return m_number
' End Get
' Set
' m_Number = Value
' End Set
' End Property
'
' Public Function MyMethod(ByVal multiplier As Integer) As Integer
' Return m_Number * multiplier
' End Function
'End Class
Dim aName As New AssemblyName("DynamicAssemblyExample")
Dim ab As AssemblyBuilder = _
AssemblyBuilder.DefineDynamicAssembly( _
aName, _
AssemblyBuilderAccess.Run)
' The module name is usually the same as the assembly name.
Dim mb As ModuleBuilder = ab.DefineDynamicModule( _
aName.Name)
Dim tb As TypeBuilder = _
mb.DefineType("MyDynamicType", TypeAttributes.Public)
' Add a private field of type Integer (Int32).
Dim fbNumber As FieldBuilder = tb.DefineField( _
"m_number", _
GetType(Integer), _
FieldAttributes.Private)
' Define a constructor that takes an integer argument and
' stores it in the private field.
Dim parameterTypes() As Type = { GetType(Integer) }
Dim ctor1 As ConstructorBuilder = _
tb.DefineConstructor( _
MethodAttributes.Public, _
CallingConventions.Standard, _
parameterTypes)
Dim ctor1IL As ILGenerator = ctor1.GetILGenerator()
' For a constructor, argument zero is a reference to the new
' instance. Push it on the stack before calling the base
' class constructor. Specify the default constructor of the
' base class (System.Object) by passing an empty array of
' types (Type.EmptyTypes) to GetConstructor.
ctor1IL.Emit(OpCodes.Ldarg_0)
ctor1IL.Emit(OpCodes.Call, _
GetType(Object).GetConstructor(Type.EmptyTypes))
' Push the instance on the stack before pushing the argument
' that is to be assigned to the private field m_number.
ctor1IL.Emit(OpCodes.Ldarg_0)
ctor1IL.Emit(OpCodes.Ldarg_1)
ctor1IL.Emit(OpCodes.Stfld, fbNumber)
ctor1IL.Emit(OpCodes.Ret)
' Define a default constructor that supplies a default value
' for the private field. For parameter types, pass the empty
' array of types or pass Nothing.
Dim ctor0 As ConstructorBuilder = tb.DefineConstructor( _
MethodAttributes.Public, _
CallingConventions.Standard, _
Type.EmptyTypes)
Dim ctor0IL As ILGenerator = ctor0.GetILGenerator()
' For a constructor, argument zero is a reference to the new
' instance. Push it on the stack before pushing the default
' value on the stack, then call constructor ctor1.
ctor0IL.Emit(OpCodes.Ldarg_0)
ctor0IL.Emit(OpCodes.Ldc_I4_S, 42)
ctor0IL.Emit(OpCodes.Call, ctor1)
ctor0IL.Emit(OpCodes.Ret)
' Define a property named Number that gets and sets the private
' field.
'
' The last argument of DefineProperty is Nothing, because the
' property has no parameters. (If you don't specify Nothing, you must
' specify an array of Type objects. For a parameterless property,
' use the built-in array with no elements: Type.EmptyTypes)
Dim pbNumber As PropertyBuilder = tb.DefineProperty( _
"Number", _
PropertyAttributes.HasDefault, _
GetType(Integer), _
Nothing)
' The property Set and property Get methods require a special
' set of attributes.
Dim getSetAttr As MethodAttributes = _
MethodAttributes.Public Or MethodAttributes.SpecialName _
Or MethodAttributes.HideBySig
' Define the "get" accessor method for Number. The method returns
' an integer and has no arguments. (Note that Nothing could be
' used instead of Types.EmptyTypes)
Dim mbNumberGetAccessor As MethodBuilder = tb.DefineMethod( _
"get_Number", _
getSetAttr, _
GetType(Integer), _
Type.EmptyTypes)
Dim numberGetIL As ILGenerator = mbNumberGetAccessor.GetILGenerator()
' For an instance property, argument zero is the instance. Load the
' instance, then load the private field and return, leaving the
' field value on the stack.
numberGetIL.Emit(OpCodes.Ldarg_0)
numberGetIL.Emit(OpCodes.Ldfld, fbNumber)
numberGetIL.Emit(OpCodes.Ret)
' Define the "set" accessor method for Number, which has no return
' type and takes one argument of type Integer (Int32).
Dim mbNumberSetAccessor As MethodBuilder = _
tb.DefineMethod( _
"set_Number", _
getSetAttr, _
Nothing, _
New Type() { GetType(Integer) })
Dim numberSetIL As ILGenerator = mbNumberSetAccessor.GetILGenerator()
' Load the instance and then the numeric argument, then store the
' argument in the field.
numberSetIL.Emit(OpCodes.Ldarg_0)
numberSetIL.Emit(OpCodes.Ldarg_1)
numberSetIL.Emit(OpCodes.Stfld, fbNumber)
numberSetIL.Emit(OpCodes.Ret)
' Last, map the "get" and "set" accessor methods to the
' PropertyBuilder. The property is now complete.
pbNumber.SetGetMethod(mbNumberGetAccessor)
pbNumber.SetSetMethod(mbNumberSetAccessor)
' Define a method that accepts an integer argument and returns
' the product of that integer and the private field m_number. This
' time, the array of parameter types is created on the fly.
Dim meth As MethodBuilder = tb.DefineMethod( _
"MyMethod", _
MethodAttributes.Public, _
GetType(Integer), _
New Type() { GetType(Integer) })
Dim methIL As ILGenerator = meth.GetILGenerator()
' To retrieve the private instance field, load the instance it
' belongs to (argument zero). After loading the field, load the
' argument one and then multiply. Return from the method with
' the return value (the product of the two numbers) on the
' execution stack.
methIL.Emit(OpCodes.Ldarg_0)
methIL.Emit(OpCodes.Ldfld, fbNumber)
methIL.Emit(OpCodes.Ldarg_1)
methIL.Emit(OpCodes.Mul)
methIL.Emit(OpCodes.Ret)
' Finish the type.
Dim t As Type = tb.CreateType()
' Because AssemblyBuilderAccess includes Run, the code can be
' executed immediately. Start by getting reflection objects for
' the method and the property.
Dim mi As MethodInfo = t.GetMethod("MyMethod")
Dim pi As PropertyInfo = t.GetProperty("Number")
' Create an instance of MyDynamicType using the default
' constructor.
Dim o1 As Object = Activator.CreateInstance(t)
' Display the value of the property, then change it to 127 and
' display it again. Use Nothing to indicate that the property
' has no index.
Console.WriteLine("o1.Number: {0}", pi.GetValue(o1, Nothing))
pi.SetValue(o1, 127, Nothing)
Console.WriteLine("o1.Number: {0}", pi.GetValue(o1, Nothing))
' Call MyMethod, passing 22, and display the return value, 22
' times 127. Arguments must be passed as an array, even when
' there is only one.
Dim arguments() As Object = { 22 }
Console.WriteLine("o1.MyMethod(22): {0}", _
mi.Invoke(o1, arguments))
' Create an instance of MyDynamicType using the constructor
' that specifies m_Number. The constructor is identified by
' matching the types in the argument array. In this case,
' the argument array is created on the fly. Display the
' property value.
Dim o2 As Object = Activator.CreateInstance(t, _
New Object() { 5280 })
Console.WriteLine("o2.Number: {0}", pi.GetValue(o2, Nothing))
End Sub
End Class
' This code produces the following output:
'
'o1.Number: 42
'o1.Number: 127
'o1.MyMethod(22): 2794
'o2.Number: 5280
下面的代码示例演示如何使用 TypeBuilder..
using System;
using System.Threading;
using System.Reflection;
using System.Reflection.Emit;
class TestILGenerator
{
public static Type DynamicDotProductGen()
{
Type ivType = null;
Type[] ctorParams = new Type[] { typeof(int),
typeof(int),
typeof(int)};
AppDomain myDomain = Thread.GetDomain();
AssemblyName myAsmName = new AssemblyName();
myAsmName.Name = "IntVectorAsm";
AssemblyBuilder myAsmBuilder = myDomain.DefineDynamicAssembly(
myAsmName,
AssemblyBuilderAccess.RunAndSave);
ModuleBuilder IntVectorModule = myAsmBuilder.DefineDynamicModule("IntVectorModule",
"Vector.dll");
TypeBuilder ivTypeBld = IntVectorModule.DefineType("IntVector",
TypeAttributes.Public);
FieldBuilder xField = ivTypeBld.DefineField("x", typeof(int),
FieldAttributes.Private);
FieldBuilder yField = ivTypeBld.DefineField("y", typeof(int),
FieldAttributes.Private);
FieldBuilder zField = ivTypeBld.DefineField("z", typeof(int),
FieldAttributes.Private);
Type objType = Type.GetType("System.Object");
ConstructorInfo objCtor = objType.GetConstructor(new Type[0]);
ConstructorBuilder ivCtor = ivTypeBld.DefineConstructor(
MethodAttributes.Public,
CallingConventions.Standard,
ctorParams);
ILGenerator ctorIL = ivCtor.GetILGenerator();
ctorIL.Emit(OpCodes.Ldarg_0);
ctorIL.Emit(OpCodes.Call, objCtor);
ctorIL.Emit(OpCodes.Ldarg_0);
ctorIL.Emit(OpCodes.Ldarg_1);
ctorIL.Emit(OpCodes.Stfld, xField);
ctorIL.Emit(OpCodes.Ldarg_0);
ctorIL.Emit(OpCodes.Ldarg_2);
ctorIL.Emit(OpCodes.Stfld, yField);
ctorIL.Emit(OpCodes.Ldarg_0);
ctorIL.Emit(OpCodes.Ldarg_3);
ctorIL.Emit(OpCodes.Stfld, zField);
ctorIL.Emit(OpCodes.Ret);
// This method will find the dot product of the stored vector
// with another.
Type[] dpParams = new Type[] { ivTypeBld };
// Here, you create a MethodBuilder containing the
// name, the attributes (public, static, private, and so on),
// the return type (int, in this case), and a array of Type
// indicating the type of each parameter. Since the sole parameter
// is a IntVector, the very class you're creating, you will
// pass in the TypeBuilder (which is derived from Type) instead of
// a Type object for IntVector, avoiding an exception.
// -- This method would be declared in C# as:
// public int DotProduct(IntVector aVector)
MethodBuilder dotProductMthd = ivTypeBld.DefineMethod(
"DotProduct",
MethodAttributes.Public,
typeof(int),
dpParams);
// A ILGenerator can now be spawned, attached to the MethodBuilder.
ILGenerator mthdIL = dotProductMthd.GetILGenerator();
// Here's the body of our function, in MSIL form. We're going to find the
// "dot product" of the current vector instance with the passed vector
// instance. For reference purposes, the equation is:
// (x1 * x2) + (y1 * y2) + (z1 * z2) = the dot product
// First, you'll load the reference to the current instance "this"
// stored in argument 0 (ldarg.0) onto the stack. Ldfld, the subsequent
// instruction, will pop the reference off the stack and look up the
// field "x", specified by the FieldInfo token "xField".
mthdIL.Emit(OpCodes.Ldarg_0);
mthdIL.Emit(OpCodes.Ldfld, xField);
// That completed, the value stored at field "x" is now atop the stack.
// Now, you'll do the same for the object reference we passed as a
// parameter, stored in argument 1 (ldarg.1). After Ldfld executed,
// you'll have the value stored in field "x" for the passed instance
// atop the stack.
mthdIL.Emit(OpCodes.Ldarg_1);
mthdIL.Emit(OpCodes.Ldfld, xField);
// There will now be two values atop the stack - the "x" value for the
// current vector instance, and the "x" value for the passed instance.
// You'll now multiply them, and push the result onto the evaluation stack.
mthdIL.Emit(OpCodes.Mul_Ovf_Un);
// Now, repeat this for the "y" fields of both vectors.
mthdIL.Emit(OpCodes.Ldarg_0);
mthdIL.Emit(OpCodes.Ldfld, yField);
mthdIL.Emit(OpCodes.Ldarg_1);
mthdIL.Emit(OpCodes.Ldfld, yField);
mthdIL.Emit(OpCodes.Mul_Ovf_Un);
// At this time, the results of both multiplications should be atop
// the stack. You'll now add them and push the result onto the stack.
mthdIL.Emit(OpCodes.Add_Ovf_Un);
// Multiply both "z" field and push the result onto the stack.
mthdIL.Emit(OpCodes.Ldarg_0);
mthdIL.Emit(OpCodes.Ldfld, zField);
mthdIL.Emit(OpCodes.Ldarg_1);
mthdIL.Emit(OpCodes.Ldfld, zField);
mthdIL.Emit(OpCodes.Mul_Ovf_Un);
// Finally, add the result of multiplying the "z" fields with the
// result of the earlier addition, and push the result - the dot product -
// onto the stack.
mthdIL.Emit(OpCodes.Add_Ovf_Un);
// The "ret" opcode will pop the last value from the stack and return it
// to the calling method. You're all done!
mthdIL.Emit(OpCodes.Ret);
ivType = ivTypeBld.CreateType();
return ivType;
}
public static void Main() {
Type IVType = null;
object aVector1 = null;
object aVector2 = null;
Type[] aVtypes = new Type[] {typeof(int), typeof(int), typeof(int)};
object[] aVargs1 = new object[] {10, 10, 10};
object[] aVargs2 = new object[] {20, 20, 20};
// Call the method to build our dynamic class.
IVType = DynamicDotProductGen();
Console.WriteLine("---");
ConstructorInfo myDTctor = IVType.GetConstructor(aVtypes);
aVector1 = myDTctor.Invoke(aVargs1);
aVector2 = myDTctor.Invoke(aVargs2);
object[] passMe = new object[1];
passMe[0] = (object)aVector2;
Console.WriteLine("(10, 10, 10) . (20, 20, 20) = {0}",
IVType.InvokeMember("DotProduct",
BindingFlags.InvokeMethod,
null,
aVector1,
passMe));
// +++ OUTPUT +++
// ---
// (10, 10, 10) . (20, 20, 20) = 600
}
}
Imports System.Threading
Imports System.Reflection
Imports System.Reflection.Emit
_
Class TestILGenerator
Public Shared Function DynamicDotProductGen() As Type
Dim ivType As Type = Nothing
Dim ctorParams() As Type = {GetType(Integer), GetType(Integer), GetType(Integer)}
Dim myDomain As AppDomain = Thread.GetDomain()
Dim myAsmName As New AssemblyName()
myAsmName.Name = "IntVectorAsm"
Dim myAsmBuilder As AssemblyBuilder = myDomain.DefineDynamicAssembly( _
myAsmName, _
AssemblyBuilderAccess.RunAndSave)
Dim IntVectorModule As ModuleBuilder = myAsmBuilder.DefineDynamicModule( _
"IntVectorModule", _
"Vector.dll")
Dim ivTypeBld As TypeBuilder = IntVectorModule.DefineType("IntVector", TypeAttributes.Public)
Dim xField As FieldBuilder = ivTypeBld.DefineField("x", _
GetType(Integer), _
FieldAttributes.Private)
Dim yField As FieldBuilder = ivTypeBld.DefineField("y", _
GetType(Integer), _
FieldAttributes.Private)
Dim zField As FieldBuilder = ivTypeBld.DefineField("z", _
GetType(Integer), _
FieldAttributes.Private)
Dim objType As Type = Type.GetType("System.Object")
Dim objCtor As ConstructorInfo = objType.GetConstructor(New Type() {})
Dim ivCtor As ConstructorBuilder = ivTypeBld.DefineConstructor( _
MethodAttributes.Public, _
CallingConventions.Standard, _
ctorParams)
Dim ctorIL As ILGenerator = ivCtor.GetILGenerator()
ctorIL.Emit(OpCodes.Ldarg_0)
ctorIL.Emit(OpCodes.Call, objCtor)
ctorIL.Emit(OpCodes.Ldarg_0)
ctorIL.Emit(OpCodes.Ldarg_1)
ctorIL.Emit(OpCodes.Stfld, xField)
ctorIL.Emit(OpCodes.Ldarg_0)
ctorIL.Emit(OpCodes.Ldarg_2)
ctorIL.Emit(OpCodes.Stfld, yField)
ctorIL.Emit(OpCodes.Ldarg_0)
ctorIL.Emit(OpCodes.Ldarg_3)
ctorIL.Emit(OpCodes.Stfld, zField)
ctorIL.Emit(OpCodes.Ret)
' Now, you'll construct the method find the dot product of two vectors. First,
' let's define the parameters that will be accepted by the method. In this case,
' it's an IntVector itself!
Dim dpParams() As Type = {ivTypeBld}
' Here, you create a MethodBuilder containing the
' name, the attributes (public, static, private, and so on),
' the return type (int, in this case), and a array of Type
' indicating the type of each parameter. Since the sole parameter
' is a IntVector, the very class you're creating, you will
' pass in the TypeBuilder (which is derived from Type) instead of
' a Type object for IntVector, avoiding an exception.
' -- This method would be declared in VB.NET as:
' Public Function DotProduct(IntVector aVector) As Integer
Dim dotProductMthd As MethodBuilder = ivTypeBld.DefineMethod("DotProduct", _
MethodAttributes.Public, GetType(Integer), _
dpParams)
' A ILGenerator can now be spawned, attached to the MethodBuilder.
Dim mthdIL As ILGenerator = dotProductMthd.GetILGenerator()
' Here's the body of our function, in MSIL form. We're going to find the
' "dot product" of the current vector instance with the passed vector
' instance. For reference purposes, the equation is:
' (x1 * x2) + (y1 * y2) + (z1 * z2) = the dot product
' First, you'll load the reference to the current instance "this"
' stored in argument 0 (ldarg.0) onto the stack. Ldfld, the subsequent
' instruction, will pop the reference off the stack and look up the
' field "x", specified by the FieldInfo token "xField".
mthdIL.Emit(OpCodes.Ldarg_0)
mthdIL.Emit(OpCodes.Ldfld, xField)
' That completed, the value stored at field "x" is now atop the stack.
' Now, you'll do the same for the object reference we passed as a
' parameter, stored in argument 1 (ldarg.1). After Ldfld executed,
' you'll have the value stored in field "x" for the passed instance
' atop the stack.
mthdIL.Emit(OpCodes.Ldarg_1)
mthdIL.Emit(OpCodes.Ldfld, xField)
' There will now be two values atop the stack - the "x" value for the
' current vector instance, and the "x" value for the passed instance.
' You'll now multiply them, and push the result onto the evaluation stack.
mthdIL.Emit(OpCodes.Mul_Ovf_Un)
' Now, repeat this for the "y" fields of both vectors.
mthdIL.Emit(OpCodes.Ldarg_0)
mthdIL.Emit(OpCodes.Ldfld, yField)
mthdIL.Emit(OpCodes.Ldarg_1)
mthdIL.Emit(OpCodes.Ldfld, yField)
mthdIL.Emit(OpCodes.Mul_Ovf_Un)
' At this time, the results of both multiplications should be atop
' the stack. You'll now add them and push the result onto the stack.
mthdIL.Emit(OpCodes.Add_Ovf_Un)
' Multiply both "z" field and push the result onto the stack.
mthdIL.Emit(OpCodes.Ldarg_0)
mthdIL.Emit(OpCodes.Ldfld, zField)
mthdIL.Emit(OpCodes.Ldarg_1)
mthdIL.Emit(OpCodes.Ldfld, zField)
mthdIL.Emit(OpCodes.Mul_Ovf_Un)
' Finally, add the result of multiplying the "z" fields with the
' result of the earlier addition, and push the result - the dot product -
' onto the stack.
mthdIL.Emit(OpCodes.Add_Ovf_Un)
' The "ret" opcode will pop the last value from the stack and return it
' to the calling method. You're all done!
mthdIL.Emit(OpCodes.Ret)
ivType = ivTypeBld.CreateType()
Return ivType
End Function 'DynamicDotProductGen
Public Shared Sub Main()
Dim IVType As Type = Nothing
Dim aVector1 As Object = Nothing
Dim aVector2 As Object = Nothing
Dim aVtypes() As Type = {GetType(Integer), GetType(Integer), GetType(Integer)}
Dim aVargs1() As Object = {10, 10, 10}
Dim aVargs2() As Object = {20, 20, 20}
' Call the method to build our dynamic class.
IVType = DynamicDotProductGen()
Dim myDTctor As ConstructorInfo = IVType.GetConstructor(aVtypes)
aVector1 = myDTctor.Invoke(aVargs1)
aVector2 = myDTctor.Invoke(aVargs2)
Console.WriteLine("---")
Dim passMe(0) As Object
passMe(0) = CType(aVector2, Object)
Console.WriteLine("(10, 10, 10) . (20, 20, 20) = {0}", _
IVType.InvokeMember("DotProduct", BindingFlags.InvokeMethod, _
Nothing, aVector1, passMe))
End Sub
End Class
' +++ OUTPUT +++
' ---
' (10, 10, 10) . (20, 20, 20) = 600
注解
TypeBuilder 是用于控制在运行时中创建动态类的根类。 它提供一组例程,用于定义类、添加方法和字段,并在模块中创建类。 可以通过调用TypeBuilder方法从动态模块创建一个新的ModuleBuilder.DefineType,该方法返回一个TypeBuilder对象。
反射发出提供用于定义类型的以下选项:
- 定义具有给定名称的类或接口。
- 使用给定名称和属性定义类或接口。
- 使用给定的名称、属性和基类定义类。
- 使用给定的名称、属性、基类和类实现的接口集定义类。
- 使用给定的名称、属性、基类和包装大小定义类。
- 定义具有给定名称、属性、基类和整体类大小的类。
- 定义具有给定名称、属性、基类、打包大小和整体类大小的类。
若要为对象表示 TypeBuilder 的不完整类型创建数组类型、指针类型或 byref 类型,请分别使用 MakeArrayType 方法、 MakePointerType 方法或 MakeByRefType 方法。
在使用类型之前,必须调用 TypeBuilder.CreateType 方法。 CreateType 完成类型的创建。 调用 CreateType 后,调用方可以使用该方法实例化类型 Activator.CreateInstance ,并使用 Type.InvokeMember 该方法调用该类型的成员。 在调用 CreateType 后再调用更改类型实现的方法是错误的。 例如,如果调用方尝试向类型添加新成员,则公共语言运行时将引发异常。
类初始值设定项使用 TypeBuilder.DefineTypeInitializer 方法创建。 DefineTypeInitializer 返回一个 ConstructorBuilder 对象。
通过调用其中 TypeBuilder.DefineNestedType 一种方法来定义嵌套类型。
特性
该 TypeBuilder 类使用 TypeAttributes 枚举进一步指定要创建的类型的特征:
- 接口是使用 TypeAttributes.Interface 属性 TypeAttributes.Abstract 指定的。
- 具体类(不能扩展的类)是使用 TypeAttributes.Sealed 特性指定的。
- 多个属性确定类型可见性。 请参见 TypeAttributes 枚举的说明。
- 如果 TypeAttributes.SequentialLayout 指定了字段,则类加载程序按从元数据中读取的顺序布局字段。 类加载程序将考虑指定的打包大小,但忽略任何指定的字段偏移量。 元数据保留发出字段定义的顺序。 即使在合并中,元数据也不会对字段定义重新排序。 仅当TypeAttributes.ExplicitLayout被指定时,加载程序才会遵循指定的字段偏移量。
已知问题
- 反射机制不会验证实现接口的非抽象类是否实现了接口中声明的所有方法。 但是,如果类未实现接口中声明的所有方法,则运行时不会加载该类。
- 虽然 TypeBuilder 派生自 Type,但 Type 类中定义的一些抽象方法未在类中 TypeBuilder 完全实现。 对这些 TypeBuilder 方法的调用将引发异常 NotSupportedException 。 可以通过使用 Type.GetType 或 Assembly.GetType 检索创建的类型,并对检索到的类型进行反射来获取所需的功能。
构造函数
| 名称 | 说明 |
|---|---|
| TypeBuilder() |
初始化 TypeBuilder 类的新实例。 |
字段
| 名称 | 说明 |
|---|---|
| UnspecifiedTypeSize |
表示未指定类型的总大小。 |
属性
| 名称 | 说明 |
|---|---|
| Assembly |
检索包含此类型定义的动态程序集。 |
| AssemblyQualifiedName |
返回由程序集的显示名称限定的此类型的全名。 |
| Attributes |
定义并创建运行时类的新实例。 |
| Attributes |
获取与 Type关联的属性。 (继承自 Type) |
| BaseType |
检索此类型的基类型。 |
| ContainsGenericParameters |
定义并创建运行时类的新实例。 |
| ContainsGenericParameters |
获取一个值,该值指示当前 Type 对象是否具有尚未被特定类型替换的类型参数。 (继承自 Type) |
| CustomAttributes |
获取包含此成员的自定义属性的集合。 (继承自 MemberInfo) |
| DeclaredConstructors |
获取由当前类型声明的构造函数的集合。 (继承自 TypeInfo) |
| DeclaredEvents |
获取由当前类型定义的事件的集合。 (继承自 TypeInfo) |
| DeclaredFields |
获取由当前类型定义的字段的集合。 (继承自 TypeInfo) |
| DeclaredMembers |
获取由当前类型定义的成员的集合。 (继承自 TypeInfo) |
| DeclaredMethods |
获取由当前类型定义的方法的集合。 (继承自 TypeInfo) |
| DeclaredNestedTypes |
获取由当前类型定义的嵌套类型的集合。 (继承自 TypeInfo) |
| DeclaredProperties |
获取由当前类型定义的属性的集合。 (继承自 TypeInfo) |
| DeclaringMethod |
获取声明当前泛型类型参数的方法。 |
| DeclaringType |
返回声明此类型的类型。 |
| FullName |
检索此类型的完整路径。 |
| GenericParameterAttributes |
获取一个值,该值指示当前泛型类型参数的协变和特殊约束。 |
| GenericParameterPosition |
获取类型参数在声明参数的泛型类型的类型参数列表中的位置。 |
| GenericTypeArguments |
定义并创建运行时类的新实例。 |
| GenericTypeArguments |
获取此类型的泛型类型参数的数组。 (继承自 Type) |
| GenericTypeParameters |
获取当前实例的泛型类型参数的数组。 (继承自 TypeInfo) |
| GUID |
检索此类型的 GUID。 |
| HasElementType |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| HasElementType |
获取一个值,该值指示当前 Type 是包含还是引用另一种类型;也就是说,当前 Type 是数组、指针还是通过引用传递。 (继承自 Type) |
| ImplementedInterfaces |
获取由当前类型实现的接口的集合。 (继承自 TypeInfo) |
| IsAbstract |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsAbstract |
获取一个值,该值指示 Type 是否是抽象的,必须重写。 (继承自 Type) |
| IsAnsiClass |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsAnsiClass |
获取一个值,该值指示是否为 |
| IsArray |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsArray |
获取一个值,该值指示类型是否为数组。 (继承自 Type) |
| IsAutoClass |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsAutoClass |
获取一个值,该值指示是否为 |
| IsAutoLayout |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsAutoLayout |
获取一个值,该值指示当前类型的字段是否由公共语言运行时自动布局。 (继承自 Type) |
| IsByRef |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsByRef |
获取一个值,该值指示是否通过引用传递 Type。 (继承自 Type) |
| IsByRefLike |
获取一个值,该值指示类型是否为类似 byref 的结构。 |
| IsClass |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsClass |
获取一个值,该值指示 Type 是类还是委托;不是值类型或接口。 (继承自 Type) |
| IsCollectible |
获取一个值,该值指示此 MemberInfo 对象是否引用一个或多个保存在可 AssemblyLoadContext回收程序集中的程序集。 (继承自 MemberInfo) |
| IsCOMObject |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsCOMObject |
获取一个值,该值指示 Type 是否为 COM 对象。 (继承自 Type) |
| IsConstructedGenericType |
获取一个值,该值指示此对象是否表示构造的泛型类型。 |
| IsContextful |
获取一个值,该值指示是否可以在上下文中托管 Type。 (继承自 Type) |
| IsEnum |
定义并创建运行时类的新实例。 |
| IsEnum |
获取一个值,该值指示当前 Type 是否表示枚举。 (继承自 Type) |
| IsExplicitLayout |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsExplicitLayout |
获取一个值,该值指示当前类型的字段是否以显式指定的偏移量布局。 (继承自 Type) |
| IsFunctionPointer |
获取一个值,该值指示当前 Type 是否为函数指针。 (继承自 Type) |
| IsGenericMethodParameter |
获取一个值,该值指示当前 Type 是否表示泛型方法定义中的类型参数。 (继承自 Type) |
| IsGenericParameter |
获取一个值,该值指示当前类型是否为泛型类型参数。 |
| IsGenericType |
获取一个值,该值指示当前类型是否为泛型类型。 |
| IsGenericTypeDefinition |
获取一个值,该值指示当前 TypeBuilder 是否表示可从中构造其他泛型类型的泛型类型定义。 |
| IsGenericTypeParameter |
获取一个值,该值指示当前 Type 是否表示泛型类型的定义中的类型参数。 (继承自 Type) |
| IsImport |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsImport |
获取一个值,该值指示 Type 是否应用了 ComImportAttribute 属性,指示它是从 COM 类型库导入的。 (继承自 Type) |
| IsInterface |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsInterface |
获取一个值,该值指示 Type 是否为接口;不是类或值类型。 (继承自 Type) |
| IsLayoutSequential |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsLayoutSequential |
获取一个值,该值指示当前类型的字段是按顺序排列的,是按照定义或发出给元数据的顺序排列的。 (继承自 Type) |
| IsMarshalByRef |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsMarshalByRef |
获取一个值,该值指示是否按引用封送 Type。 (继承自 Type) |
| IsNested |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsNested |
获取一个值,该值指示当前 Type 对象是否表示其定义嵌套在另一类型的定义中的类型。 (继承自 Type) |
| IsNestedAssembly |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsNestedAssembly |
获取一个值,该值指示 Type 是否嵌套且仅在其自己的程序集内可见。 (继承自 Type) |
| IsNestedFamANDAssem |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsNestedFamANDAssem |
获取一个值,该值指示 Type 是否嵌套,并且仅对属于其自己的系列和自己的程序集的类可见。 (继承自 Type) |
| IsNestedFamily |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsNestedFamily |
获取一个值,该值指示 Type 是否嵌套并在其自己的系列内可见。 (继承自 Type) |
| IsNestedFamORAssem |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsNestedFamORAssem |
获取一个值,该值指示 Type 是嵌套的,并且仅对属于其自己的系列或其自己的程序集的类可见。 (继承自 Type) |
| IsNestedPrivate |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsNestedPrivate |
获取一个值,该值指示 Type 是否嵌套并声明为私有。 (继承自 Type) |
| IsNestedPublic |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsNestedPublic |
获取一个值,该值指示类是否嵌套并声明为公共类。 (继承自 Type) |
| IsNotPublic |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsNotPublic |
获取一个值,该值指示 Type 是否未声明为公共。 (继承自 Type) |
| IsPointer |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsPointer |
获取一个值,该值指示 Type 是否为指针。 (继承自 Type) |
| IsPrimitive |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsPrimitive |
获取一个值,该值指示 Type 是否为基元类型之一。 (继承自 Type) |
| IsPublic |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsPublic |
获取一个值,该值指示 Type 是否声明为公共。 (继承自 Type) |
| IsSealed |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsSealed |
获取一个值,该值指示是否声明 Type 密封。 (继承自 Type) |
| IsSecurityCritical |
获取一个值,该值指示当前类型是安全关键型还是安全安全关键型,因此可以执行关键操作。 |
| IsSecuritySafeCritical |
获取一个值,该值指示当前类型是否为安全安全关键;也就是说,它是否可以执行关键操作,并且可以通过透明代码访问。 |
| IsSecurityTransparent |
获取一个值,该值指示当前类型是否透明,因此无法执行关键操作。 |
| IsSerializable |
定义并创建运行时类的新实例。 |
| IsSerializable |
已过时.
获取一个值,该值指示 Type 是否可序列化二进制。 (继承自 Type) |
| IsSignatureType |
获取一个值,该值指示类型是否为签名类型。 (继承自 Type) |
| IsSpecialName |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsSpecialName |
获取一个值,该值指示类型是否具有需要特殊处理的名称。 (继承自 Type) |
| IsSZArray |
定义并创建运行时类的新实例。 |
| IsTypeDefinition |
定义并创建运行时类的新实例。 |
| IsUnicodeClass |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsUnicodeClass |
获取一个值,该值指示是否为 |
| IsUnmanagedFunctionPointer |
获取一个值,该值指示当前 Type 是否为非托管函数指针。 (继承自 Type) |
| IsValueType |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsValueType |
获取一个值,该值指示 Type 是否为值类型。 (继承自 Type) |
| IsVariableBoundArray |
定义并创建运行时类的新实例。 |
| IsVariableBoundArray |
获取一个值,该值指示类型是可以表示多维数组还是具有任意下限的数组的数组类型。 (继承自 Type) |
| IsVisible |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| IsVisible |
获取一个值,该值指示程序集外部的代码是否可以访问 Type。 (继承自 Type) |
| MemberType |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| MemberType |
获取一个 MemberTypes 值,该值指示此成员是类型或嵌套类型。 (继承自 Type) |
| MetadataToken |
获取标识元数据中当前动态模块的令牌。 |
| MetadataToken |
获取标识元数据元素的值。 (继承自 MemberInfo) |
| Module |
检索包含此类型定义的动态模块。 |
| Name |
检索此类型的名称。 |
| Namespace |
检索在其中定义此项 |
| PackingSize |
检索此类型的打包大小。 |
| PackingSizeCore |
在派生类中重写时,获取此类型的打包大小。 |
| ReflectedType |
返回用于获取此类型的类型。 |
| Size |
检索类型的总大小。 |
| SizeCore |
在派生类中重写时,获取类型的总大小。 |
| StructLayoutAttribute |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| StructLayoutAttribute |
获取描述当前类型的布局的 StructLayoutAttribute。 (继承自 Type) |
| TypeHandle |
动态模块不支持。 |
| TypeInitializer |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |
| TypeInitializer |
获取类型的初始值设定项。 (继承自 Type) |
| TypeToken |
返回此类型的类型标记。 |
| UnderlyingSystemType |
返回此 |
| UnderlyingSystemType |
定义并创建运行时类的新实例。 (继承自 TypeInfo) |