Сборка не сохраняется правильно

#.net #reflection #reflection.emit

Вопрос:

У меня есть очень простой код для создания сборки и вызова метода для содержащегося типа. Метод вызывается и выполняется правильно, однако, когда я просматриваю сгенерированную сборку с помощью отражателя, я не вижу типа.

Ниже приведен пример кода:

 namespace ConsoleApplication2
{
    class Proggy
    {
        public static void Main(string[] args)
        {
            var ab = AppDomain.CurrentDomain.DefineDynamicAssembly(
                new AssemblyName() { Name = "MyAssembly" },
                AssemblyBuilderAccess.RunAndSave);
            var module = ab.DefineDynamicModule(ab.GetName().Name);
            var typeBuilder = module.DefineType("MyType");
            var ctr = typeBuilder.DefineConstructor(MethodAttributes.Public, 
                CallingConventions.Standard, Type.EmptyTypes);
            var ilgc = ctr.GetILGenerator();
            ilgc.Emit(OpCodes.Ldarg_0);
            ilgc.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
            ilgc.Emit(OpCodes.Ret);
            var method = typeBuilder.DefineMethod("MyMethod", MethodAttributes.Public,
                typeof(int), new[] { typeof(string) });
            var ilg = method.GetILGenerator();
            ilg.Emit(OpCodes.Ldarg_1);
            ilg.EmitCall(OpCodes.Callvirt, typeof(string).GetProperty("Length").GetGetMethod(),
                null);
            ilg.Emit(OpCodes.Ret);
            var type = typeBuilder.CreateType();
            ab.Save("mytestasm.dll");
            var inst = Activator.CreateInstance(type);
            Console.WriteLine(type.InvokeMember("MyMethod", BindingFlags.InvokeMethod, null, inst,
                new[] { "MyTestString" }));
            Console.ReadLine();
        }
    }
}
 

а вот соответствующая разборка с отражателя:

 .assembly MyAssembly
{
    .ver 0:0:0:0
    .hash algorithm 0x00008004
}
.module RefEmit_OnDiskManifestModule
// MVID: {0B944140-58D9-430E-A867-DE0AD0A8701F}
// Target Runtime Version: v2.0.50727
 

… и …

 {
    .class private auto ansi <Module>
    {
    }
}
 

Кто-нибудь может помочь мне правильно сохранить сборку?

Ответ №1:

Хитрость заключается в том, чтобы использовать версию «постоянного модуля» метода DefineDynamicModule в экземпляре AssemblyBuilder. То есть вместо:

 var module = ab.DefineDynamicModule(ab.GetName().Name);
 

используйте что-то вроде:

 var module = ab.DefineDynamicModule(ab.GetName().Name, ab.GetName().Name   ".mod");
 

После этого соответствующий модуль появляется в сборке после сохранения.

Ответ №2:

Я не уверен, почему этот тип не добавляется.

Однако другой способ сделать это-динамически создавать код, просто передавая строку, содержащую код вашего класса. Я думаю, что это немного проще, чем описанный выше способ, так как вы можете просто создать код с помощью строкового конструктора и протестировать его в студии.

Вот код, который я использую для создания dll:

 print(" Microsoft.CSharp.CSharpCodeProvider objCodeProvider = new Microsoft.CSharp.CSharpCodeProvider();
        string strCode = "using System;"   Environment.NewLine   "using System.Data;"   Environment.NewLine   "using DC.Common;"   Environment.NewLine   ""   Environment.NewLine   "using System.Data.SqlClient;"   Environment.NewLine   "using System.Configuration;"   Environment.NewLine   ""   Environment.NewLine   Environment.NewLine   BaseClassFile   Environment.NewLine   BaseManagerFile   Environment.NewLine;
        string strSourceModule = BuilderSettings.ExportDir   "/"   BuilderSettings.ProjectName   "/"    "BaseFile.cs";

        FileHelper.WriteAllText(strSourceModule, strCode);
        FileHelper.WriteAllText(BuilderSettings.ExportDir   "/"   BuilderSettings.ProjectName   "/"   "test.txt", strCode);

        ICodeCompiler icc = objCodeProvider.CreateCompiler();
        string OutputPath = BuilderSettings.ExportDir   "/"   BuilderSettings.ProjectName   "/"   BuilderSettings.ProjectName   ".dll";
        CompilerParameters parameters = new CompilerParameters();
        CompilerResults results;

        parameters.GenerateExecutable = false;
        parameters.OutputAssembly = OutputPath;
        parameters.GenerateInMemory = false;
        parameters.IncludeDebugInformation = false;

        //Add required assemblies
        DynamicLinkLibraries.Clear();

        //User defined
        DynamicLinkLibraries.Add(@"d:wwwroot\DC.CommonbinDebugDC.Common.dll");

        //System
        DynamicLinkLibraries.Add("System.dll");
        DynamicLinkLibraries.Add("System.Data.dll");
        DynamicLinkLibraries.Add("mscorlib.dll");
        DynamicLinkLibraries.Add("System.xml.dll");
        DynamicLinkLibraries.Add("System.web.dll");
        DynamicLinkLibraries.Add("System.configuration.dll");

        //Any dynamic assembly adding must be done here
        foreach (string strLibrary in DynamicLinkLibraries)
        {
            parameters.ReferencedAssemblies.Add(strLibrary);
        }

            results = icc.CompileAssemblyFromSource(parameters, strCode);

            if (results.Errors.Count > 0)
            {
                //report any compilation errors
                string strErrors = "Compilation failed:"   Environment.NewLine;

                foreach (CompilerError oError in results.Errors)
                {
                    strErrors = strErrors   "Line number "   oError.Line   ", Error Number: "   oError.ErrorNumber   ", '"   oError.ErrorText   ";";

                }

                throw new Exception("Error in CompileSourceCode(): "   Environment.NewLine   strErrors);
            }

            objCodeProvider = null;
            icc = null;
            parameters = null;");