无法使用Mono Cecil设置类型的基类

时间:2014-12-10 12:33:09

标签: c# .net mono mono.cecil

我正在尝试使用Mono Cecil来操纵DLL。我想要做的是从System.MarshalByRefObject将某些类的基类型设置为mscorlib.dll。我使用以下代码。

var assembly = AssemblyDefinition.ReadAssembly(inputtarget);
var types = assembly.MainModule.Types;
var myTypesToChange = types.Where(...).Select(t => t);
var baseType = AssemblyDefinition.ReadAssembly(@"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscorlib.dll").MainModule.Types.Where(t => t.Name.Contains("MarshalByRefObject")).Select(t => t).First();
foreach (var myType in myTypesToChange)
{
    myType.BaseType = baseType;
}
assembly.Write(outputtarget);

在输出中未设置基本类型!

当我将BaseType设置为从现有程序集中选择的TypeReference时,它正在正确设置基本类型。

我相信我所做的与this reply中有关代码项目文章"Reweaving IL code with Mono.Cecil"的评论中的建议非常类似:

  

“是的,您可以重写任何类的基本类型:”

var assembly = AssemblyDefinition.ReadAssembly(AssemblyPath); 
var mainModule = assembly.MainModule;

var companyType = mainModule.Types.First(t => t.Name == "Company");
var ownerType = mainModule.Types.First(t => t.Name == "Owner");

ownerType.BaseType = companyType;
assembly.Write(AssemblyPath);

这应该很容易!我做错了什么?

1 个答案:

答案 0 :(得分:3)

问题是不考虑装配元数据。每个程序集都包含元数据,其中包含与程序集引用和类型用法相关的信息。

您需要做的是在mainModule中导入MarshalByRefObject类型:

var assembly = assemblyDef.AssemblyDefinition;
var types = assembly.MainModule.Types;
var myTypesToChange = types.Select(t => t);
var baseType = AssemblyDefinition.ReadAssembly(@"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscorlib.dll").MainModule.Types.Where(t => t.Name.Contains("MarshalByRefObject")).Select(t => t).First();
foreach (var myType in myTypesToChange)
{
    myType.BaseType = mainModule.Import(baseType);
}

除了扩展元数据之外,还必须更改构造函数的CIL代码以调用新基类的构造函数而不是原始构造函数。

最后,一个建议。我认为MarshalByRefObject的TypeReference可以以更优雅的方式提取:

var baseType = mainModule.Import(typeof (MarshalByRefObject));
for (...)
{
    myType.BaseType = baseType;
}