Emit学习(题外话)-使生成的dll像正常dll一样可被使用
Emit学习(题外话)-使生成的dll像正常dll一样可被使用
- 摘要:本文介绍让使用Emit生成的dll像正常dll一样被其他项目使用,并提供详细的实现代码供参考。
在写了第一篇关于Emit的随笔之后,我试着将生成的dll引入新建的项目并使用动态生成的类,然而很不幸,运行时出错了:Could not load type 'Hello' from assembly 'Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'。
生成动态dll的代码如下:
AssemblyName assemName = new AssemblyName();
assemName.Name = "Test";
AssemblyBuilder asmBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly(
assemName,
AssemblyBuilderAccess.RunAndSave);
var mdlBldr = asmBuilder.DefineDynamicModule("Main", "Main.dll");
var typeBldr = mdlBldr.DefineType("Hello", TypeAttributes.Public);
var methodBldr = typeBldr.DefineMethod(
"SayHello",
MethodAttributes.Public | MethodAttributes.Static,
null,//return type
null//parameter type
);
var il = methodBldr.GetILGenerator();//获取il生成器
il.Emit(OpCodes.Ldstr, "Hello, World");
il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
il.Emit(OpCodes.Call, typeof(Console).GetMethod("ReadLine"));
il.Emit(OpCodes.Pop);//读入的值会被推送至evaluation stack,而本方法是没有返回值的,因此,需要将栈上的值抛弃
il.Emit(OpCodes.Ret);
typeBldr.CreateType();
asmBuilder.Save("Main.dll");
生成的dll大家可以用Reflector看下,也没什么问题。可是为什么就会出错呢?于是开始‘翻箱倒柜’,查阅了MSDN上AssemblyBuilder,ModuleBuilder中的大量方法,不过终究没有发现能解决这个问题的。
于是我又对比了该程序集与其他程序集的区别,发现没有版本等信息。因此我又寻思给这个程序集添加版本信息。在MSDN找到一段设置版本信息的实例代码后,发现加了版本信息的dll的确可以使用了。然而,问题真的是这样造成的吗?我还是不太确定。我又一点点的删减代码,直到变成和上面的版本没多少差别:
AssemblyName assemName = new AssemblyName();
assemName.Name = "EmittedAssembly";
AssemblyBuilder asmBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly(
assemName,
AssemblyBuilderAccess.RunAndSave);
var mdlBldr = asmBuilder.DefineDynamicModule("Main", "Main.dll");
var typeBldr = mdlBldr.DefineType("Hello", TypeAttributes.Public);
var methodBldr = typeBldr.DefineMethod(
"SayHello",
MethodAttributes.Public | MethodAttributes.Static,
null,//return type
null//parameter type
);
var il = methodBldr.GetILGenerator();//获取il生成器
il.Emit(OpCodes.Ldstr, "Hello, World");
il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
il.Emit(OpCodes.Call, typeof(Console).GetMethod("ReadLine"));
il.Emit(OpCodes.Pop);//读入的值会被推送至evaluation stack,而本方法是没有返回值的,因此,需要将栈上的值抛弃
il.Emit(OpCodes.Ret);
typeBldr.CreateType();
asmBuilder.Save("Main.dll");
这时生成的dll仍旧是可以使用的。我不禁好奇难道是对程序集名称长度有限制(因为上面两段只有程序集名称不一样)?因此我开始尝试增加长度(比地一段的长)但一直到程序集名称长度等于或者大于第二段代码时,仍旧不可用。更有意思的时,如果稍对第二段代码的名称做点变动,就会报错。尴尬!难道只有使用EmittedAssembly作为程序集名称生成的dll才能被使用?
浙公网安备 33010602011771号