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 之後,嘗試執行更改類型的實作的任何方法,都是錯誤的。 例如,如果呼叫端嘗試將新成員新增至類型,Common Language Runtime 會擲回例外狀況。
類別初始化運算式是使用 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來擷取所建立的類型,並反映所擷取的類型,以取得所需的功能。
建構函式
| 名稱 | Description |
|---|---|
| TypeBuilder() |
初始化 TypeBuilder 類別的新執行個體。 |
欄位
| 名稱 | Description |
|---|---|
| UnspecifiedTypeSize |
代表該類型的總大小未被指定。 |
屬性
| 名稱 | Description |
|---|---|
| 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) |