如何建立一个组装和保存它…
本文关键字:保存 何建立 建立 一个 | 更新日期: 2023-09-27 18:16:51
有许多c#代码片段演示构建。net程序集。
代码成功运行,但问题是保存的程序集不包含生成的代码。-即使我已经设置RunAndSave属性为AssemblyBuilder。
谁能告诉我如何正确地构建和保存与生成的类,方法等汇编?
谢谢!
这是我在demo中使用的一些代码。这对于一个简单的例子来说有点多,但它是有效的。保存在BuildGenericType方法中完成。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection.Emit;
using System.Reflection;
namespace ReflectionEmit
{
class Program
{
delegate int DoMath(int value);
static DoMath mathFunc;
static void Main(string[] args)
{
CreateCode(27, true);
CreateCode(27, false);
BuildGenericType();
Console.ReadKey();
}
private static void CreateCode(int value, bool square)
{
mathFunc = (DoMath)BuildMethod(square).CreateDelegate(typeof(DoMath));
int result = mathFunc(value);
Console.WriteLine("Result for {0} was {1}", value, result );
}
private static DynamicMethod BuildMethod(bool square)
{
Type[] methodArgs = { typeof(int) };
DynamicMethod mthMeth = new DynamicMethod(
"Square",
typeof(int),
methodArgs,
typeof(ReflectionEmit.Program).Module);
ILGenerator il = mthMeth.GetILGenerator();
if (square)
{
il.Emit(OpCodes.Ldarg_0); //Loads argument at index 0 into the evaluation stack
il.Emit(OpCodes.Conv_I8); //Converts the value on top of the evaluation stack to int64
il.Emit(OpCodes.Dup); //Copies the top most value on the evaluation stack, then pushes it to the top
il.Emit(OpCodes.Mul); //Multiplies two values then pushes result to top of evaluation stack
il.Emit(OpCodes.Ret); //Returns from the current method, pushing a return value (if present) from the callee's evaluation stack onto the caller's evaluation stack.
}
else
{
il.Emit(OpCodes.Ldarg_0); //Loads argument at index 0 into the evaluation stack
il.Emit(OpCodes.Conv_I8); //Converts the value on top of the evaluation stack to int64
il.Emit(OpCodes.Dup); //Copies the top most value on the evaluation stack, then pushes it to the top
il.Emit(OpCodes.Add); //Adds two values then pushes result to top of evaluation stack
il.Emit(OpCodes.Ret); //Returns from the current method, pushing a return value (if present) from the callee's evaluation stack onto the caller's evaluation stack.
}
return mthMeth;
}
private static void BuildGenericType()
{
//Define assembly
AppDomain dom = AppDomain.CurrentDomain;
AssemblyName asmName = new AssemblyName("domath");
AssemblyBuilder asm = dom.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave);
//Define a dynamic module
ModuleBuilder mod = asm.DefineDynamicModule(asmName.Name, asmName.Name + ".dll");
//Define a class
TypeBuilder asmType = mod.DefineType("OurClass", TypeAttributes.Public);
//Define the generic type parameters
string[] typeNames = { "TFirst", "TSecond" };
GenericTypeParameterBuilder[] genTypes = asmType.DefineGenericParameters(typeNames);
GenericTypeParameterBuilder TFirst = genTypes[0];
GenericTypeParameterBuilder TSecond = genTypes[1];
//Define generic constraints
TFirst.SetGenericParameterAttributes(GenericParameterAttributes.DefaultConstructorConstraint | GenericParameterAttributes.ReferenceTypeConstraint);
TSecond.SetBaseTypeConstraint(typeof(SomeBaseClass));
Type[] interfaceTypes = {typeof(InterfaceA), typeof(InterfaceB) };
TSecond.SetInterfaceConstraints(interfaceTypes);
//Define a field
FieldBuilder fld1 = asmType.DefineField("Field1", TFirst, FieldAttributes.Private);
//Define method
Type listOf = typeof(List<>);
Type listOfTFirst = listOf.MakeGenericType(TFirst);
Type[] paramTypes = { TFirst.MakeArrayType() };
MethodBuilder asmMethod = asmType.DefineMethod("SomeMethod", MethodAttributes.Public | MethodAttributes.Static, listOfTFirst, paramTypes);
//Define Method Body
ILGenerator il = asmMethod.GetILGenerator();
Type ienumOf = typeof(IEnumerable<>);
Type tFromListOf = listOf.GetGenericArguments()[0];
Type ienumOfT = ienumOf.MakeGenericType(tFromListOf);
Type[] ctorArgs = { ienumOfT };
ConstructorInfo ctorPrep = listOf.GetConstructor(ctorArgs);
ConstructorInfo ctor = TypeBuilder.GetConstructor(listOfTFirst, ctorPrep);
il.Emit(OpCodes.Ldarg_0); //Loads the argument at index 0 onto the evaluation stack.
il.Emit(OpCodes.Newobj, ctor); //Creates a new object or a new instance of a value type, pushing an object reference (type O) onto the evaluation stack.
il.Emit(OpCodes.Ret); //Returns from the current method, pushing a return value (if present) from the callee's evaluation stack onto the caller's evaluation stack.
//Create type and save file
Type finished = asmType.CreateType();
asm.Save(asmName.Name + ".dll");
}
}
public interface InterfaceA { }
public interface InterfaceB { }
public class SomeBaseClass
{
}
}
作为替代,也许你可以试试罗斯林?http://blogs.msdn.com/b/csharpfaq/archive/2011/12/02/introduction-to-the-roslyn-scripting-api.aspx
以Microsoft文档示例作为参考源代码,我猜测OP缺少的重要部分是在调用DefineDynamicModule
时使用相同的名称用于第二个参数(fileName
),以及在AssemblyBuilder
上调用Save
时使用第一个参数。当在这些地方使用相同的名称时,动态创建的模块及其所有类型等将与程序集一起保存。
在示例代码中,在文档中,这个名称是按照aName.Name + ".dll"
构建的:
AssemblyName aName = new AssemblyName("DynamicAssemblyExample");
AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.RunAndSave); // Include Save access!
ModuleBuilder mb = ab.DefineDynamicModule(aName.Name, aName.Name + ".dll"); // *Same name here ..*
// ... (Other code building types, methods etc.)
ab.Save(aName.Name + ".dll"); // *... and here*
其他说明:
文档示例代码中的注释提到
"对于单模块程序集,模块名称通常是程序集名称加上扩展名。"
注释部分说明
"如果动态程序集包含多个动态模块,则程序集的清单文件名应该与模块的名称匹配指定为DefineDynamicModule方法的第一个参数。
也许,这是一个线索,找出使用相同的名称,如上所述。实际上,它也可以使用DefineDynamicModule
的一个参数重载,并按文件名命名模块。
注意 DefineDynamicModule(String, String)
重载在。net Core或。net 5.0中不可用。