我正在编写一个使用System.Reflection.Emit
API生成磁盘上.NET程序集的编译器。编译器本身是针对.NET 4.5构建的,但生成的代码仅引用可移植类库中的类型。但是,当尝试从Windows Phone 8项目引用生成的程序集时,Visual Studio会抱怨A reference to a higher version or incompatible assembly cannot be added to the project
。
在反编译器中打开生成的程序集时,我可以看到它引用了两个PCL加上mscorlib 4.0.0.0
,而我知道PCL应该引用mscorlib 2.0.5.0
。
有没有办法让System.Reflection.Emit
API生成PCL,或者是我唯一选择迁移到Mono.Cecil
?
答案 0 :(得分:5)
好的,我会回答我自己的问题。
我没有发现System.Reflection.Emit
API可以生成引用另一版mscorlib
的程序集而不是当前进程使用的程序集的证据。实际上,采用System.Type
参数和其他反射对象的API可能会添加对查询其Type.Assembly
属性的结果的引用,该属性对应于正在使用的mscorlib
版本。
但是,可移植类库与System.Reflection.Emit
生成的库没有什么不同,因此可以在事后修补程序集“使它们可移植”。 免责声明:这需要熟悉PE文件格式,可能会产生无法预料的副作用,但它对我有用:
生成程序集时,使用AssemblyBuilder.SetCustomAttribute
将此属性添加到程序集中:
[System.Runtime.Versioning.TargetFrameworkAttribute(".NETPortable,Version=v4.0,Profile=Profile136", FrameworkDisplayName = ".NET Portable Subset")]
这是粗略的:在调用AssemblyBuilder.Save
之后,打开一个读/写文件流到生成的程序集,遍历PE,COFF,COM,CLI和元数据表头来定位AssemblyRef
的{{1}}表格行。将mscorlib
的引用版本修改为mscorlib
,将2.0.5.0
添加到其标记(“retargetable”)并将其公钥标记blob更新为0x100
。
请注意,如果您使用其他框架程序集,则可能还需要修补其引用(我尚未对此进行测试)。不然,瞧!该程序集现在是可移植的,例如,可以在Windows Phone项目中使用。
(...或只使用0x7CEC85D7BEA7798E
/ Mono.Cecil
...)
修改:可以找到我使用的代码on github。这是一个巨大的黑客攻击,因此通常的免责声明适用,使用风险自负。