问题
I am trying to use Mono Cecil to manipulate a DLL. What I want to do is to set the base type of some classes to System.MarshalByRefObject
from mscorlib.dll
. I am using the following code.
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);
In the output the base type is not set!
When I am setting the BaseType
to a TypeReference
selected from the existing assembly, it is setting the base type correctly.
I believe that what I do is very similar to the way it is done as suggested in this reply to a comment about the Code Project article "Reweaving IL code with Mono.Cecil":
"Yes, you can rewrite the base type of any class:"
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);
This should be easy! What I am doing wrong?
回答1:
The problem is that assembly metadata is not taken into account. Each assembly has metadata which contains information related to assembly references and type usages.
What you have to do is to import the MarshalByRefObject type in mainModule:
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);
}
Besides the metadata is extended, CIL code of the constructors have to be changed to invoke a constructor of the new base class instead of the original.
Finally, a suggestion. I think TypeReference for MarshalByRefObject can be extracted in a more elegant manner:
var baseType = mainModule.Import(typeof (MarshalByRefObject));
for (...)
{
myType.BaseType = baseType;
}
来源:https://stackoverflow.com/questions/27401118/cannot-set-the-base-class-of-a-type-with-mono-cecil