如何更改TypeDefinition的BaseType(在其他程序集中定义)?

时间:2014-04-07 12:00:54

标签: mono.cecil

我一直在努力改变特定场景中TypeDefinition的BaseType。假设我们有以下装配。

Assembly1:

Class MyAssembly1Class:Test1Class {}

Assembly2:

Class MyAssembly2Class:Test2Class {}

现在我想将“Assembly1”中定义的“MyAssembly1Class”的Base类更改为assembly2中定义的“MyAssembly2Class”。即。

Class MyAssembly1Class:MyAssembly2Class {}

如何实现这一目标?

我尝试了以下代码:

   public static void UpdateDerviedTextBoxTypes(AssemblyDefinition main, AssemblyDefinition otherAssembly)
    {
        TypeReference injectionTextBoxRef = null;

        injectionTextBoxRef = otherAssembly.MainModule.GetType("MyAssembly2Class. Test2Class");

        if (injectionTextBoxRef == null)
        {
            return;
        }

        foreach (TypeDefinition type in main.MainModule.Types)
        {
            if (type.IsClass && type.BaseType != null && type.BaseType.FullName == "MyAssembly1Class.Test1Class")
            {
                type.BaseType = injectionTextBoxRef;
            }
        }
    }

虽然它不会抛出任何异常或错误,但是在ildasm.exe上加载输出dll时,我发现basetype没有改变。

1 个答案:

答案 0 :(得分:1)

让我们说你要改变的派生类是:

类MyTextBox:TextBox { }

你的班级

类NewTextBox:TextBox {

}

如果在ildasm中打开MyTextClass构造函数定义,您会注意到一条指令调用BaseClass构造函数,即TextBox ::。ctor() 必须用NewTextBox reference.i.e替换它。 NewTextBox ::。构造函数()

试试这个:

injectionTextBoxRef:键入我们要替换的类的引用。

textBoxRef:键入要替换的类的基类的引用。

foreach (TypeDefinition type in main.MainModule.Types)           

{

if (type.IsClass && type.BaseType != null && (type.BaseType.FullName == 
  "System.Windows.Controls.TextBox" || type.BaseType.FullName == "Windows.UI.Xaml.Controls.TextBox"))
            {
                type.BaseType = injectionTextBoxRef;
                foreach (MethodDefinition method in type.Methods)
                {
                    if (method.Body == null)
                        continue;
                    if (method.IsConstructor)
                    {
                        for (int i = 0; i < method.Body.Instructions.Count; i++)
                        {
                            var inst = method.Body.Instructions[i];
                            if (inst.Operand == null)
                                continue;

                            if (inst.OpCode == OpCodes.Call && (inst.Operand.ToString().Contains("System.Void System.Windows.Controls.TextBox::.ctor()") || inst.Operand.ToString().Contains("System.Void Windows.UI.Xaml.Controls.TextBox::.ctor()")))
                            {
                                var next = method.Body.Instructions[i + 1];
                                var temp = inst;
                                inst = Instruction.Create(OpCodes.Call, textBoxRef);
                                inst.Next = temp.Next;
                                inst.Offset = temp.Offset;
                                inst.Previous = temp.Previous;
                                inst.SequencePoint = temp.SequencePoint;
                                var processor = method.Body.GetILProcessor();
                                processor.Remove(temp);
                                processor.InsertBefore(next, inst);
                            }
                        }
                    }
                }
            }
        }