#.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;");