AssemblyBuilder.Save Метод
Определение
Важно!
Некоторые сведения относятся к предварительной версии продукта, в которую до выпуска могут быть внесены существенные изменения. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
Сохраняет динамическую сборку на диск.
Перегрузки
Save(String) |
Сохраняет динамическую сборку на диск. |
Save(String, PortableExecutableKinds, ImageFileMachine) |
Сохраняет эту динамическую сборку на диске, указывая природу кода в исполняемых файлах сборки и целевую платформу. |
Save(String)
- Исходный код:
- AssemblyBuilder.cs
Сохраняет динамическую сборку на диск.
public:
void Save(System::String ^ assemblyFileName);
public void Save (string assemblyFileName);
member this.Save : string -> unit
Public Sub Save (assemblyFileName As String)
Параметры
- assemblyFileName
- String
Имя файла сборки.
Исключения
Длина assemblyFileName
равна нулю.
-или-
В сборке есть два или более файлов ресурсов модулей с тем же именем.
-или-
Целевой каталог сборки недопустим.
-или-
assemblyFileName
не является простым именем файла (например, содержит каталог или букву диска), или в этой сборке определено несколько неуправляемых ресурсов, включая ресурс сведений о версии.
-или-
Строка CultureInfo
в AssemblyCultureAttribute не является допустимой строкой, и DefineVersionInfoResource(String, String, String, String, String) был вызван до вызова этого метода.
assemblyFileName
имеет значение null
.
Во время сохранения возникает ошибка вывода.
CreateType() не был вызван для какого-либо типа в модулях сборки, которые должны быть записаны на диск.
Примеры
В следующем примере кода создается динамическая сборка, а затем она сохраняется на локальном диске с помощью Save
.
using namespace System;
using namespace System::Text;
using namespace System::Threading;
using namespace System::Reflection;
using namespace System::Reflection::Emit;
// The Point class is the class we will reflect on and copy into our
// dynamic assembly. The public static function PointMain() will be used
// as our entry point.
//
// We are constructing the type seen here dynamically, and will write it
// out into a .exe file for later execution from the command-line.
// ---
// __gc class Point {
//
// private:
// int x;
// int y;
//
// public:
// Point(int ix, int iy) {
//
// this->x = ix;
// this->y = iy;
//
// }
//
// int DotProduct (Point* p) {
//
// return ((this->x * p->x) + (this->y * p->y));
//
// }
//
// static void PointMain() {
//
// Console::Write(S"Enter the 'x' value for point 1: ");
// int x1 = Convert::ToInt32(Console::ReadLine());
//
// Console::Write(S"Enter the 'y' value for point 1: ");
// int y1 = Convert::ToInt32(Console::ReadLine());
//
// Console::Write(S"Enter the 'x' value for point 2: ");
// int x2 = Convert::ToInt32(Console::ReadLine());
//
// Console::Write(S"Enter the 'y' value for point 2: ");
// int y2 = Convert::ToInt32(Console::ReadLine());
//
// Point* p1 = new Point(x1, y1);
// Point* p2 = new Point(x2, y2);
//
// Console::WriteLine(S"( {0}, {1}) . ( {2}, {3}) = {4}.",
// __box(x1), __box(y1), __box(x2), __box(y2), p1->DotProduct(p2));
//
// }
//
// };
// ---
Type^ BuildDynAssembly()
{
Type^ pointType = nullptr;
AppDomain^ currentDom = Thread::GetDomain();
Console::Write( "Please enter a name for your new assembly: " );
StringBuilder^ asmFileNameBldr = gcnew StringBuilder;
asmFileNameBldr->Append( Console::ReadLine() );
asmFileNameBldr->Append( ".exe" );
String^ asmFileName = asmFileNameBldr->ToString();
AssemblyName^ myAsmName = gcnew AssemblyName;
myAsmName->Name = "MyDynamicAssembly";
AssemblyBuilder^ myAsmBldr = currentDom->DefineDynamicAssembly( myAsmName, AssemblyBuilderAccess::RunAndSave );
// We've created a dynamic assembly space - now, we need to create a module
// within it to reflect the type Point into.
ModuleBuilder^ myModuleBldr = myAsmBldr->DefineDynamicModule( asmFileName, asmFileName );
TypeBuilder^ myTypeBldr = myModuleBldr->DefineType( "Point" );
FieldBuilder^ xField = myTypeBldr->DefineField( "x", int::typeid, FieldAttributes::Private );
FieldBuilder^ yField = myTypeBldr->DefineField( "y", int::typeid, FieldAttributes::Private );
// Build the constructor.
Type^ objType = Type::GetType( "System.Object" );
ConstructorInfo^ objCtor = objType->GetConstructor( gcnew array<Type^>(0) );
array<Type^>^temp4 = {int::typeid,int::typeid};
array<Type^>^ctorParams = temp4;
ConstructorBuilder^ pointCtor = myTypeBldr->DefineConstructor( MethodAttributes::Public, CallingConventions::Standard, ctorParams );
ILGenerator^ ctorIL = pointCtor->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::Ret );
// Build the DotProduct method.
Console::WriteLine( "Constructor built." );
array<Type^>^temp0 = {myTypeBldr};
MethodBuilder^ pointDPBldr = myTypeBldr->DefineMethod( "DotProduct", MethodAttributes::Public, int::typeid, temp0 );
ILGenerator^ dpIL = pointDPBldr->GetILGenerator();
dpIL->Emit( OpCodes::Ldarg_0 );
dpIL->Emit( OpCodes::Ldfld, xField );
dpIL->Emit( OpCodes::Ldarg_1 );
dpIL->Emit( OpCodes::Ldfld, xField );
dpIL->Emit( OpCodes::Mul_Ovf_Un );
dpIL->Emit( OpCodes::Ldarg_0 );
dpIL->Emit( OpCodes::Ldfld, yField );
dpIL->Emit( OpCodes::Ldarg_1 );
dpIL->Emit( OpCodes::Ldfld, yField );
dpIL->Emit( OpCodes::Mul_Ovf_Un );
dpIL->Emit( OpCodes::Add_Ovf_Un );
dpIL->Emit( OpCodes::Ret );
// Build the PointMain method.
Console::WriteLine( "DotProduct built." );
MethodBuilder^ pointMainBldr = myTypeBldr->DefineMethod( "PointMain", static_cast<MethodAttributes>(MethodAttributes::Public | MethodAttributes::Static), void::typeid, nullptr );
pointMainBldr->InitLocals = true;
ILGenerator^ pmIL = pointMainBldr->GetILGenerator();
// We have four methods that we wish to call, and must represent as
// MethodInfo tokens:
// - void Console::WriteLine(String*)
// - String* Console::ReadLine()
// - int Convert::Int32(String*)
// - void Console::WriteLine(String*, Object*[])
array<Type^>^temp1 = {String::typeid};
MethodInfo^ writeMI = Console::typeid->GetMethod( "Write", temp1 );
MethodInfo^ readLineMI = Console::typeid->GetMethod( "ReadLine", gcnew array<Type^>(0) );
array<Type^>^temp2 = {String::typeid};
MethodInfo^ convertInt32MI = Convert::typeid->GetMethod( "ToInt32", temp2 );
array<Type^>^temp5 = {String::typeid,array<Object^>::typeid};
array<Type^>^wlParams = temp5;
MethodInfo^ writeLineMI = Console::typeid->GetMethod( "WriteLine", wlParams );
// Although we could just refer to the local variables by
// index (short ints for Ldloc/Stloc, bytes for LdLoc_S/Stloc_S),
// this time, we'll use LocalBuilders for clarity and to
// demonstrate their usage and syntax.
LocalBuilder^ x1LB = pmIL->DeclareLocal( int::typeid );
LocalBuilder^ y1LB = pmIL->DeclareLocal( int::typeid );
LocalBuilder^ x2LB = pmIL->DeclareLocal( int::typeid );
LocalBuilder^ y2LB = pmIL->DeclareLocal( int::typeid );
LocalBuilder^ point1LB = pmIL->DeclareLocal( myTypeBldr );
LocalBuilder^ point2LB = pmIL->DeclareLocal( myTypeBldr );
LocalBuilder^ tempObjArrLB = pmIL->DeclareLocal( array<Object^>::typeid );
pmIL->Emit( OpCodes::Ldstr, "Enter the 'x' value for point 1: " );
pmIL->EmitCall( OpCodes::Call, writeMI, nullptr );
pmIL->EmitCall( OpCodes::Call, readLineMI, nullptr );
pmIL->EmitCall( OpCodes::Call, convertInt32MI, nullptr );
pmIL->Emit( OpCodes::Stloc, x1LB );
pmIL->Emit( OpCodes::Ldstr, "Enter the 'y' value for point 1: " );
pmIL->EmitCall( OpCodes::Call, writeMI, nullptr );
pmIL->EmitCall( OpCodes::Call, readLineMI, nullptr );
pmIL->EmitCall( OpCodes::Call, convertInt32MI, nullptr );
pmIL->Emit( OpCodes::Stloc, y1LB );
pmIL->Emit( OpCodes::Ldstr, "Enter the 'x' value for point 2: " );
pmIL->EmitCall( OpCodes::Call, writeMI, nullptr );
pmIL->EmitCall( OpCodes::Call, readLineMI, nullptr );
pmIL->EmitCall( OpCodes::Call, convertInt32MI, nullptr );
pmIL->Emit( OpCodes::Stloc, x2LB );
pmIL->Emit( OpCodes::Ldstr, "Enter the 'y' value for point 2: " );
pmIL->EmitCall( OpCodes::Call, writeMI, nullptr );
pmIL->EmitCall( OpCodes::Call, readLineMI, nullptr );
pmIL->EmitCall( OpCodes::Call, convertInt32MI, nullptr );
pmIL->Emit( OpCodes::Stloc, y2LB );
pmIL->Emit( OpCodes::Ldloc, x1LB );
pmIL->Emit( OpCodes::Ldloc, y1LB );
pmIL->Emit( OpCodes::Newobj, pointCtor );
pmIL->Emit( OpCodes::Stloc, point1LB );
pmIL->Emit( OpCodes::Ldloc, x2LB );
pmIL->Emit( OpCodes::Ldloc, y2LB );
pmIL->Emit( OpCodes::Newobj, pointCtor );
pmIL->Emit( OpCodes::Stloc, point2LB );
pmIL->Emit( OpCodes::Ldstr, "( {0}, {1}) . ( {2}, {3}) = {4}." );
pmIL->Emit( OpCodes::Ldc_I4_5 );
pmIL->Emit( OpCodes::Newarr, Object::typeid );
pmIL->Emit( OpCodes::Stloc, tempObjArrLB );
pmIL->Emit( OpCodes::Ldloc, tempObjArrLB );
pmIL->Emit( OpCodes::Ldc_I4_0 );
pmIL->Emit( OpCodes::Ldloc, x1LB );
pmIL->Emit( OpCodes::Box, int::typeid );
pmIL->Emit( OpCodes::Stelem_Ref );
pmIL->Emit( OpCodes::Ldloc, tempObjArrLB );
pmIL->Emit( OpCodes::Ldc_I4_1 );
pmIL->Emit( OpCodes::Ldloc, y1LB );
pmIL->Emit( OpCodes::Box, int::typeid );
pmIL->Emit( OpCodes::Stelem_Ref );
pmIL->Emit( OpCodes::Ldloc, tempObjArrLB );
pmIL->Emit( OpCodes::Ldc_I4_2 );
pmIL->Emit( OpCodes::Ldloc, x2LB );
pmIL->Emit( OpCodes::Box, int::typeid );
pmIL->Emit( OpCodes::Stelem_Ref );
pmIL->Emit( OpCodes::Ldloc, tempObjArrLB );
pmIL->Emit( OpCodes::Ldc_I4_3 );
pmIL->Emit( OpCodes::Ldloc, y2LB );
pmIL->Emit( OpCodes::Box, int::typeid );
pmIL->Emit( OpCodes::Stelem_Ref );
pmIL->Emit( OpCodes::Ldloc, tempObjArrLB );
pmIL->Emit( OpCodes::Ldc_I4_4 );
pmIL->Emit( OpCodes::Ldloc, point1LB );
pmIL->Emit( OpCodes::Ldloc, point2LB );
pmIL->EmitCall( OpCodes::Callvirt, pointDPBldr, nullptr );
pmIL->Emit( OpCodes::Box, int::typeid );
pmIL->Emit( OpCodes::Stelem_Ref );
pmIL->Emit( OpCodes::Ldloc, tempObjArrLB );
pmIL->EmitCall( OpCodes::Call, writeLineMI, nullptr );
pmIL->Emit( OpCodes::Ret );
Console::WriteLine( "PointMain (entry point) built." );
pointType = myTypeBldr->CreateType();
Console::WriteLine( "Type completed." );
myAsmBldr->SetEntryPoint( pointMainBldr );
myAsmBldr->Save( asmFileName );
Console::WriteLine( "Assembly saved as ' {0}'.", asmFileName );
Console::WriteLine( "Type ' {0}' at the prompt to run your new dynamically generated dot product calculator.", asmFileName );
// After execution, this program will have generated and written to disk,
// in the directory you executed it from, a program named
// <name_you_entered_here>.exe. You can run it by typing
// the name you gave it during execution, in the same directory where
// you executed this program.
return pointType;
}
int main()
{
Type^ myType = BuildDynAssembly();
Console::WriteLine( "---" );
// Let's invoke the type 'Point' created in our dynamic assembly.
array<Object^>^temp3 = {nullptr,nullptr};
Object^ ptInstance = Activator::CreateInstance( myType, temp3 );
myType->InvokeMember( "PointMain", BindingFlags::InvokeMethod, nullptr, ptInstance, gcnew array<Object^>(0) );
}
using System;
using System.Text;
using System.Threading;
using System.Reflection;
using System.Reflection.Emit;
// The Point class is the class we will reflect on and copy into our
// dynamic assembly. The public static function PointMain() will be used
// as our entry point.
//
// We are constructing the type seen here dynamically, and will write it
// out into a .exe file for later execution from the command-line.
// ---
// class Point {
//
// private int x;
// private int y;
//
// public Point(int ix, int iy) {
//
// this.x = ix;
// this.y = iy;
//
// }
//
// public int DotProduct (Point p) {
//
// return ((this.x * p.x) + (this.y * p.y));
//
// }
//
// public static void PointMain() {
//
// Console.Write("Enter the 'x' value for point 1: ");
// int x1 = Convert.ToInt32(Console.ReadLine());
//
// Console.Write("Enter the 'y' value for point 1: ");
// int y1 = Convert.ToInt32(Console.ReadLine());
//
// Console.Write("Enter the 'x' value for point 2: ");
// int x2 = Convert.ToInt32(Console.ReadLine());
//
// Console.Write("Enter the 'y' value for point 2: ");
// int y2 = Convert.ToInt32(Console.ReadLine());
//
// Point p1 = new Point(x1, y1);
// Point p2 = new Point(x2, y2);
//
// Console.WriteLine("({0}, {1}) . ({2}, {3}) = {4}.",
// x1, y1, x2, y2, p1.DotProduct(p2));
//
// }
//
// }
// ---
class AssemblyBuilderDemo {
public static Type BuildDynAssembly() {
Type pointType = null;
AppDomain currentDom = Thread.GetDomain();
Console.Write("Please enter a name for your new assembly: ");
StringBuilder asmFileNameBldr = new StringBuilder();
asmFileNameBldr.Append(Console.ReadLine());
asmFileNameBldr.Append(".exe");
string asmFileName = asmFileNameBldr.ToString();
AssemblyName myAsmName = new AssemblyName();
myAsmName.Name = "MyDynamicAssembly";
AssemblyBuilder myAsmBldr = currentDom.DefineDynamicAssembly(
myAsmName,
AssemblyBuilderAccess.RunAndSave);
// We've created a dynamic assembly space - now, we need to create a module
// within it to reflect the type Point into.
ModuleBuilder myModuleBldr = myAsmBldr.DefineDynamicModule(asmFileName,
asmFileName);
TypeBuilder myTypeBldr = myModuleBldr.DefineType("Point");
FieldBuilder xField = myTypeBldr.DefineField("x", typeof(int),
FieldAttributes.Private);
FieldBuilder yField = myTypeBldr.DefineField("y", typeof(int),
FieldAttributes.Private);
// Build the constructor.
Type objType = Type.GetType("System.Object");
ConstructorInfo objCtor = objType.GetConstructor(new Type[0]);
Type[] ctorParams = new Type[] {typeof(int), typeof(int)};
ConstructorBuilder pointCtor = myTypeBldr.DefineConstructor(
MethodAttributes.Public,
CallingConventions.Standard,
ctorParams);
ILGenerator ctorIL = pointCtor.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.Ret);
// Build the DotProduct method.
Console.WriteLine("Constructor built.");
MethodBuilder pointDPBldr = myTypeBldr.DefineMethod("DotProduct",
MethodAttributes.Public,
typeof(int),
new Type[] {myTypeBldr});
ILGenerator dpIL = pointDPBldr.GetILGenerator();
dpIL.Emit(OpCodes.Ldarg_0);
dpIL.Emit(OpCodes.Ldfld, xField);
dpIL.Emit(OpCodes.Ldarg_1);
dpIL.Emit(OpCodes.Ldfld, xField);
dpIL.Emit(OpCodes.Mul_Ovf_Un);
dpIL.Emit(OpCodes.Ldarg_0);
dpIL.Emit(OpCodes.Ldfld, yField);
dpIL.Emit(OpCodes.Ldarg_1);
dpIL.Emit(OpCodes.Ldfld, yField);
dpIL.Emit(OpCodes.Mul_Ovf_Un);
dpIL.Emit(OpCodes.Add_Ovf_Un);
dpIL.Emit(OpCodes.Ret);
// Build the PointMain method.
Console.WriteLine("DotProduct built.");
MethodBuilder pointMainBldr = myTypeBldr.DefineMethod("PointMain",
MethodAttributes.Public |
MethodAttributes.Static,
typeof(void),
null);
pointMainBldr.InitLocals = true;
ILGenerator pmIL = pointMainBldr.GetILGenerator();
// We have four methods that we wish to call, and must represent as
// MethodInfo tokens:
// - void Console.WriteLine(string)
// - string Console.ReadLine()
// - int Convert.Int32(string)
// - void Console.WriteLine(string, object[])
MethodInfo writeMI = typeof(Console).GetMethod(
"Write",
new Type[] {typeof(string)});
MethodInfo readLineMI = typeof(Console).GetMethod(
"ReadLine",
new Type[0]);
MethodInfo convertInt32MI = typeof(Convert).GetMethod(
"ToInt32",
new Type[] {typeof(string)});
Type[] wlParams = new Type[] {typeof(string), typeof(object[])};
MethodInfo writeLineMI = typeof(Console).GetMethod(
"WriteLine",
wlParams);
// Although we could just refer to the local variables by
// index (short ints for Ldloc/Stloc, bytes for LdLoc_S/Stloc_S),
// this time, we'll use LocalBuilders for clarity and to
// demonstrate their usage and syntax.
LocalBuilder x1LB = pmIL.DeclareLocal(typeof(int));
LocalBuilder y1LB = pmIL.DeclareLocal(typeof(int));
LocalBuilder x2LB = pmIL.DeclareLocal(typeof(int));
LocalBuilder y2LB = pmIL.DeclareLocal(typeof(int));
LocalBuilder point1LB = pmIL.DeclareLocal(myTypeBldr);
LocalBuilder point2LB = pmIL.DeclareLocal(myTypeBldr);
LocalBuilder tempObjArrLB = pmIL.DeclareLocal(typeof(object[]));
pmIL.Emit(OpCodes.Ldstr, "Enter the 'x' value for point 1: ");
pmIL.EmitCall(OpCodes.Call, writeMI, null);
pmIL.EmitCall(OpCodes.Call, readLineMI, null);
pmIL.EmitCall(OpCodes.Call, convertInt32MI, null);
pmIL.Emit(OpCodes.Stloc, x1LB);
pmIL.Emit(OpCodes.Ldstr, "Enter the 'y' value for point 1: ");
pmIL.EmitCall(OpCodes.Call, writeMI, null);
pmIL.EmitCall(OpCodes.Call, readLineMI, null);
pmIL.EmitCall(OpCodes.Call, convertInt32MI, null);
pmIL.Emit(OpCodes.Stloc, y1LB);
pmIL.Emit(OpCodes.Ldstr, "Enter the 'x' value for point 2: ");
pmIL.EmitCall(OpCodes.Call, writeMI, null);
pmIL.EmitCall(OpCodes.Call, readLineMI, null);
pmIL.EmitCall(OpCodes.Call, convertInt32MI, null);
pmIL.Emit(OpCodes.Stloc, x2LB);
pmIL.Emit(OpCodes.Ldstr, "Enter the 'y' value for point 2: ");
pmIL.EmitCall(OpCodes.Call, writeMI, null);
pmIL.EmitCall(OpCodes.Call, readLineMI, null);
pmIL.EmitCall(OpCodes.Call, convertInt32MI, null);
pmIL.Emit(OpCodes.Stloc, y2LB);
pmIL.Emit(OpCodes.Ldloc, x1LB);
pmIL.Emit(OpCodes.Ldloc, y1LB);
pmIL.Emit(OpCodes.Newobj, pointCtor);
pmIL.Emit(OpCodes.Stloc, point1LB);
pmIL.Emit(OpCodes.Ldloc, x2LB);
pmIL.Emit(OpCodes.Ldloc, y2LB);
pmIL.Emit(OpCodes.Newobj, pointCtor);
pmIL.Emit(OpCodes.Stloc, point2LB);
pmIL.Emit(OpCodes.Ldstr, "({0}, {1}) . ({2}, {3}) = {4}.");
pmIL.Emit(OpCodes.Ldc_I4_5);
pmIL.Emit(OpCodes.Newarr, typeof(Object));
pmIL.Emit(OpCodes.Stloc, tempObjArrLB);
pmIL.Emit(OpCodes.Ldloc, tempObjArrLB);
pmIL.Emit(OpCodes.Ldc_I4_0);
pmIL.Emit(OpCodes.Ldloc, x1LB);
pmIL.Emit(OpCodes.Box, typeof(int));
pmIL.Emit(OpCodes.Stelem_Ref);
pmIL.Emit(OpCodes.Ldloc, tempObjArrLB);
pmIL.Emit(OpCodes.Ldc_I4_1);
pmIL.Emit(OpCodes.Ldloc, y1LB);
pmIL.Emit(OpCodes.Box, typeof(int));
pmIL.Emit(OpCodes.Stelem_Ref);
pmIL.Emit(OpCodes.Ldloc, tempObjArrLB);
pmIL.Emit(OpCodes.Ldc_I4_2);
pmIL.Emit(OpCodes.Ldloc, x2LB);
pmIL.Emit(OpCodes.Box, typeof(int));
pmIL.Emit(OpCodes.Stelem_Ref);
pmIL.Emit(OpCodes.Ldloc, tempObjArrLB);
pmIL.Emit(OpCodes.Ldc_I4_3);
pmIL.Emit(OpCodes.Ldloc, y2LB);
pmIL.Emit(OpCodes.Box, typeof(int));
pmIL.Emit(OpCodes.Stelem_Ref);
pmIL.Emit(OpCodes.Ldloc, tempObjArrLB);
pmIL.Emit(OpCodes.Ldc_I4_4);
pmIL.Emit(OpCodes.Ldloc, point1LB);
pmIL.Emit(OpCodes.Ldloc, point2LB);
pmIL.EmitCall(OpCodes.Callvirt, pointDPBldr, null);
pmIL.Emit(OpCodes.Box, typeof(int));
pmIL.Emit(OpCodes.Stelem_Ref);
pmIL.Emit(OpCodes.Ldloc, tempObjArrLB);
pmIL.EmitCall(OpCodes.Call, writeLineMI, null);
pmIL.Emit(OpCodes.Ret);
Console.WriteLine("PointMain (entry point) built.");
pointType = myTypeBldr.CreateType();
Console.WriteLine("Type completed.");
myAsmBldr.SetEntryPoint(pointMainBldr);
myAsmBldr.Save(asmFileName);
Console.WriteLine("Assembly saved as '{0}'.", asmFileName);
Console.WriteLine("Type '{0}' at the prompt to run your new " +
"dynamically generated dot product calculator.",
asmFileName);
// After execution, this program will have generated and written to disk,
// in the directory you executed it from, a program named
// <name_you_entered_here>.exe. You can run it by typing
// the name you gave it during execution, in the same directory where
// you executed this program.
return pointType;
}
public static void Main() {
Type myType = BuildDynAssembly();
Console.WriteLine("---");
// Let's invoke the type 'Point' created in our dynamic assembly.
object ptInstance = Activator.CreateInstance(myType, new object[] {0,0});
myType.InvokeMember("PointMain",
BindingFlags.InvokeMethod,
null,
ptInstance,
new object[0]);
}
}
Imports System.Text
Imports System.Threading
Imports System.Reflection
Imports System.Reflection.Emit
_
' The Point class is the class we will reflect on and copy into our
' dynamic assembly. The public static function PointMain() will be used
' as our entry point.
'
' We are constructing the type seen here dynamically, and will write it
' out into a .exe file for later execution from the command-line.
' ---
' Class Point
'
' Private x As Integer
' Private y As Integer
'
'
' Public Sub New(ix As Integer, iy As Integer)
'
' Me.x = ix
' Me.y = iy
' End Sub
'
'
' Public Function DotProduct(p As Point) As Integer
'
' Return Me.x * p.x + Me.y * p.y
' End Function 'DotProduct
'
'
' Public Shared Sub Main()
'
' Console.Write("Enter the 'x' value for point 1: ")
' Dim x1 As Integer = Convert.ToInt32(Console.ReadLine())
'
' Console.Write("Enter the 'y' value for point 1: ")
' Dim y1 As Integer = Convert.ToInt32(Console.ReadLine())
'
' Console.Write("Enter the 'x' value for point 2: ")
' Dim x2 As Integer = Convert.ToInt32(Console.ReadLine())
'
' Console.Write("Enter the 'y' value for point 2: ")
' Dim y2 As Integer = Convert.ToInt32(Console.ReadLine())
'
' Dim p1 As New Point(x1, y1)
' Dim p2 As New Point(x2, y2)
'
' Console.WriteLine("({0}, {1}) . ({2}, {3}) = {4}.", x1, y1, x2, y2, p1.DotProduct(p2))
' End Sub
' End Class
' ---
Class AssemblyBuilderDemo
Public Shared Function BuildDynAssembly() As Type
Dim pointType As Type = Nothing
Dim currentDom As AppDomain = Thread.GetDomain()
Console.Write("Please enter a name for your new assembly: ")
Dim asmFileNameBldr As New StringBuilder()
asmFileNameBldr.Append(Console.ReadLine())
asmFileNameBldr.Append(".exe")
Dim asmFileName As String = asmFileNameBldr.ToString()
Dim myAsmName As New AssemblyName()
myAsmName.Name = "MyDynamicAssembly"
Dim myAsmBldr As AssemblyBuilder = currentDom.DefineDynamicAssembly(myAsmName, _
AssemblyBuilderAccess.RunAndSave)
' We've created a dynamic assembly space - now, we need to create a module
' within it to reflect the type Point into.
Dim myModuleBldr As ModuleBuilder = myAsmBldr.DefineDynamicModule(asmFileName, _
asmFileName)
Dim myTypeBldr As TypeBuilder = myModuleBldr.DefineType("Point")
Dim xField As FieldBuilder = myTypeBldr.DefineField("x", GetType(Integer), _
FieldAttributes.Private)
Dim yField As FieldBuilder = myTypeBldr.DefineField("y", GetType(Integer), _
FieldAttributes.Private)
' Build the constructor.
Dim objType As Type = Type.GetType("System.Object")
Dim objCtor As ConstructorInfo = objType.GetConstructor(New Type() {})
Dim ctorParams() As Type = {GetType(Integer), GetType(Integer)}
Dim pointCtor As ConstructorBuilder = myTypeBldr.DefineConstructor( _
MethodAttributes.Public, _
CallingConventions.Standard, _
ctorParams)
Dim ctorIL As ILGenerator = pointCtor.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.Ret)
' Build the DotProduct method.
Console.WriteLine("Constructor built.")
Dim pointDPBldr As MethodBuilder = myTypeBldr.DefineMethod("DotProduct", _
MethodAttributes.Public, _
GetType(Integer), _
New Type(0) {myTypeBldr})
Dim dpIL As ILGenerator = pointDPBldr.GetILGenerator()
dpIL.Emit(OpCodes.Ldarg_0)
dpIL.Emit(OpCodes.Ldfld, xField)
dpIL.Emit(OpCodes.Ldarg_1)
dpIL.Emit(OpCodes.Ldfld, xField)
dpIL.Emit(OpCodes.Mul_Ovf_Un)
dpIL.Emit(OpCodes.Ldarg_0)
dpIL.Emit(OpCodes.Ldfld, yField)
dpIL.Emit(OpCodes.Ldarg_1)
dpIL.Emit(OpCodes.Ldfld, yField)
dpIL.Emit(OpCodes.Mul_Ovf_Un)
dpIL.Emit(OpCodes.Add_Ovf_Un)
dpIL.Emit(OpCodes.Ret)
' Build the PointMain method.
Console.WriteLine("DotProduct built.")
Dim pointMainBldr As MethodBuilder = myTypeBldr.DefineMethod("PointMain", _
MethodAttributes.Public Or _
MethodAttributes.Static, _
Nothing, Nothing)
pointMainBldr.InitLocals = True
Dim pmIL As ILGenerator = pointMainBldr.GetILGenerator()
' We have four methods that we wish to call, and must represent as
' MethodInfo tokens:
' - Sub Console.WriteLine(string)
' - Function Console.ReadLine() As String
' - Function Convert.Int32(string) As Int
' - Sub Console.WriteLine(string, object[])
Dim writeMI As MethodInfo = GetType(Console).GetMethod("Write", _
New Type(0) {GetType(String)})
Dim readLineMI As MethodInfo = GetType(Console).GetMethod("ReadLine", _
New Type() {})
Dim convertInt32MI As MethodInfo = GetType(Convert).GetMethod("ToInt32", _
New Type(0) {GetType(String)})
Dim wlParams() As Type = {GetType(String), GetType(Object())}
Dim writeLineMI As MethodInfo = GetType(Console).GetMethod("WriteLine", wlParams)
' Although we could just refer to the local variables by
' index (short ints for Ldloc/Stloc, bytes for LdLoc_S/Stloc_S),
' this time, we'll use LocalBuilders for clarity and to
' demonstrate their usage and syntax.
Dim x1LB As LocalBuilder = pmIL.DeclareLocal(GetType(Integer))
Dim y1LB As LocalBuilder = pmIL.DeclareLocal(GetType(Integer))
Dim x2LB As LocalBuilder = pmIL.DeclareLocal(GetType(Integer))
Dim y2LB As LocalBuilder = pmIL.DeclareLocal(GetType(Integer))
Dim point1LB As LocalBuilder = pmIL.DeclareLocal(myTypeBldr)
Dim point2LB As LocalBuilder = pmIL.DeclareLocal(myTypeBldr)
Dim tempObjArrLB As LocalBuilder = pmIL.DeclareLocal(GetType(Object()))
pmIL.Emit(OpCodes.Ldstr, "Enter the 'x' value for point 1: ")
pmIL.EmitCall(OpCodes.Call, writeMI, Nothing)
pmIL.EmitCall(OpCodes.Call, readLineMI, Nothing)
pmIL.EmitCall(OpCodes.Call, convertInt32MI, Nothing)
pmIL.Emit(OpCodes.Stloc, x1LB)
pmIL.Emit(OpCodes.Ldstr, "Enter the 'y' value for point 1: ")
pmIL.EmitCall(OpCodes.Call, writeMI, Nothing)
pmIL.EmitCall(OpCodes.Call, readLineMI, Nothing)
pmIL.EmitCall(OpCodes.Call, convertInt32MI, Nothing)
pmIL.Emit(OpCodes.Stloc, y1LB)
pmIL.Emit(OpCodes.Ldstr, "Enter the 'x' value for point 2: ")
pmIL.EmitCall(OpCodes.Call, writeMI, Nothing)
pmIL.EmitCall(OpCodes.Call, readLineMI, Nothing)
pmIL.EmitCall(OpCodes.Call, convertInt32MI, Nothing)
pmIL.Emit(OpCodes.Stloc, x2LB)
pmIL.Emit(OpCodes.Ldstr, "Enter the 'y' value for point 2: ")
pmIL.EmitCall(OpCodes.Call, writeMI, Nothing)
pmIL.EmitCall(OpCodes.Call, readLineMI, Nothing)
pmIL.EmitCall(OpCodes.Call, convertInt32MI, Nothing)
pmIL.Emit(OpCodes.Stloc, y2LB)
pmIL.Emit(OpCodes.Ldloc, x1LB)
pmIL.Emit(OpCodes.Ldloc, y1LB)
pmIL.Emit(OpCodes.Newobj, pointCtor)
pmIL.Emit(OpCodes.Stloc, point1LB)
pmIL.Emit(OpCodes.Ldloc, x2LB)
pmIL.Emit(OpCodes.Ldloc, y2LB)
pmIL.Emit(OpCodes.Newobj, pointCtor)
pmIL.Emit(OpCodes.Stloc, point2LB)
pmIL.Emit(OpCodes.Ldstr, "({0}, {1}) . ({2}, {3}) = {4}.")
pmIL.Emit(OpCodes.Ldc_I4_5)
pmIL.Emit(OpCodes.Newarr, GetType([Object]))
pmIL.Emit(OpCodes.Stloc, tempObjArrLB)
pmIL.Emit(OpCodes.Ldloc, tempObjArrLB)
pmIL.Emit(OpCodes.Ldc_I4_0)
pmIL.Emit(OpCodes.Ldloc, x1LB)
pmIL.Emit(OpCodes.Box, GetType(Integer))
pmIL.Emit(OpCodes.Stelem_Ref)
pmIL.Emit(OpCodes.Ldloc, tempObjArrLB)
pmIL.Emit(OpCodes.Ldc_I4_1)
pmIL.Emit(OpCodes.Ldloc, y1LB)
pmIL.Emit(OpCodes.Box, GetType(Integer))
pmIL.Emit(OpCodes.Stelem_Ref)
pmIL.Emit(OpCodes.Ldloc, tempObjArrLB)
pmIL.Emit(OpCodes.Ldc_I4_2)
pmIL.Emit(OpCodes.Ldloc, x2LB)
pmIL.Emit(OpCodes.Box, GetType(Integer))
pmIL.Emit(OpCodes.Stelem_Ref)
pmIL.Emit(OpCodes.Ldloc, tempObjArrLB)
pmIL.Emit(OpCodes.Ldc_I4_3)
pmIL.Emit(OpCodes.Ldloc, y2LB)
pmIL.Emit(OpCodes.Box, GetType(Integer))
pmIL.Emit(OpCodes.Stelem_Ref)
pmIL.Emit(OpCodes.Ldloc, tempObjArrLB)
pmIL.Emit(OpCodes.Ldc_I4_4)
pmIL.Emit(OpCodes.Ldloc, point1LB)
pmIL.Emit(OpCodes.Ldloc, point2LB)
pmIL.EmitCall(OpCodes.Callvirt, pointDPBldr, Nothing)
pmIL.Emit(OpCodes.Box, GetType(Integer))
pmIL.Emit(OpCodes.Stelem_Ref)
pmIL.Emit(OpCodes.Ldloc, tempObjArrLB)
pmIL.EmitCall(OpCodes.Call, writeLineMI, Nothing)
pmIL.Emit(OpCodes.Ret)
Console.WriteLine("PointMain (entry point) built.")
pointType = myTypeBldr.CreateType()
Console.WriteLine("Type completed.")
myAsmBldr.SetEntryPoint(pointMainBldr)
myAsmBldr.Save(asmFileName)
Console.WriteLine("Assembly saved as '{0}'.", asmFileName)
Console.WriteLine("Type '{0}' at the prompt to run your new " + "dynamically generated dot product calculator.", asmFileName)
' After execution, this program will have generated and written to disk,
' in the directory you executed it from, a program named
' <name_you_entered_here>.exe. You can run it by typing
' the name you gave it during execution, in the same directory where
' you executed this program.
Return pointType
End Function 'BuildDynAssembly
Public Shared Sub Main()
Dim myType As Type = BuildDynAssembly()
Console.WriteLine("---")
' Let's invoke the type 'Point' created in our dynamic assembly.
Dim ptInstance As Object = Activator.CreateInstance(myType, New Object(1) {0, 0})
myType.InvokeMember("PointMain", BindingFlags.InvokeMethod, _
Nothing, ptInstance, New Object() {})
End Sub
End Class
Комментарии
Примечание
Сохранение динамической сборки на диск поддерживается только в платформа .NET Framework.
Этот метод сохраняет все непереходные динамические модули, определенные в этой динамической сборке. Временные динамические модули не сохраняются. Имя файла сборки может совпадать с именем одного из модулей. В этом случае манифест сборки хранится в этом модуле.
assemblyFileName
могут отличаться от имен всех модулей, содержащихся в сборке. В этом случае файл сборки содержит только манифест сборки.
Для каждого, ResourceWriter полученного с помощью DefineResource, этот метод записывает RESOURCES-файл и вызывает Close для закрытия потока.
Должно assemblyFileName
быть простым именем файла без диска или компонента каталога. Чтобы создать сборку в определенном каталоге, используйте один из DefineDynamicAssembly методов, который принимает аргумент целевого каталога.
В платформа .NET Framework версии 2.0 эта перегрузка Save метода эквивалентна вызову перегрузки Save(String, PortableExecutableKinds, ImageFileMachine) метода с ILOnly для portableExecutableKind
параметра и I386 для imageFileMachine
параметра .
Применяется к
Save(String, PortableExecutableKinds, ImageFileMachine)
Сохраняет эту динамическую сборку на диске, указывая природу кода в исполняемых файлах сборки и целевую платформу.
public:
void Save(System::String ^ assemblyFileName, System::Reflection::PortableExecutableKinds portableExecutableKind, System::Reflection::ImageFileMachine imageFileMachine);
public void Save (string assemblyFileName, System.Reflection.PortableExecutableKinds portableExecutableKind, System.Reflection.ImageFileMachine imageFileMachine);
member this.Save : string * System.Reflection.PortableExecutableKinds * System.Reflection.ImageFileMachine -> unit
Public Sub Save (assemblyFileName As String, portableExecutableKind As PortableExecutableKinds, imageFileMachine As ImageFileMachine)
Параметры
- assemblyFileName
- String
Имя файла сборки.
- portableExecutableKind
- PortableExecutableKinds
Побитовое сочетание значений PortableExecutableKinds, определяющее природу кода.
- imageFileMachine
- ImageFileMachine
Одно из значений ImageFileMachine, определяющее целевую платформу.
Исключения
Длина assemblyFileName
равна нулю.
-или-
В сборке есть два или более файлов ресурсов модулей с тем же именем.
-или-
Целевой каталог сборки недопустим.
-или-
assemblyFileName
не является простым именем файла (например, содержит каталог или букву диска), или в этой сборке определено несколько неуправляемых ресурсов, включая ресурсы сведений о версии.
-или-
Строка CultureInfo
в AssemblyCultureAttribute не является допустимой строкой, и DefineVersionInfoResource(String, String, String, String, String) был вызван до вызова этого метода.
assemblyFileName
имеет значение null
.
Во время сохранения возникает ошибка вывода.
CreateType() не был вызван для какого-либо типа в модулях сборки, которые должны быть записаны на диск.
Комментарии
Примечание
Сохранение динамической сборки на диск поддерживается только в платформа .NET Framework.
Если imageFileMachine
и portableExecutableKind
несовместимы, imageFileMachine
имеет приоритет над portableExecutableKind
. Исключение не выдается. Например, если указать с PortableExecutableKinds.PE32Plusпомощью ImageFileMachine.I386 , PortableExecutableKinds.PE32Plus параметр игнорируется.
Этот метод сохраняет все непереходные динамические модули, определенные в этой динамической сборке. Временные динамические модули не сохраняются. Имя файла сборки может совпадать с именем одного из модулей. В этом случае манифест сборки хранится в этом модуле.
assemblyFileName
могут отличаться от имен всех модулей, содержащихся в сборке. В этом случае файл сборки содержит только манифест сборки.
Для каждого, ResourceWriter полученного с помощью DefineResource, этот метод записывает RESOURCES-файл и вызывает Close для закрытия потока.
Должно assemblyFileName
быть простым именем файла без диска или компонента каталога. Чтобы создать сборку в определенном каталоге, используйте один из DefineDynamicAssembly методов, который принимает аргумент целевого каталога.