如何建立一个组装和保存它…

本文关键字:保存 何建立 建立 一个 | 更新日期: 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中不可用。