How do i change the BaseType (define in other asse

2019-05-20 17:39发布

问题:

I have been struggling to change the BaseType of a TypeDefinition in specific scenario. Let's say we have below assemblies.

Assembly1:

Class MyAssembly1Class: Test1Class{}

Assembly2:

Class MyAssembly2Class: Test2Class{}

Now I want to change the Base class of "MyAssembly1Class" defined in "Assembly1" to "MyAssembly2Class" defined in assembly2. i.e.

Class MyAssembly1Class: MyAssembly2Class{}

How can this be achieved?

I tried code below:

   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;
            }
        }
    }

though it does not throw any exception or error, but on loading the output dll on ildasm.exe, I observed that basetype is not changed.

回答1:

Let's say the derived class that you are going to change is:

class MyTextBox: TextBox { }

Your's class

Class NewTextBox:TextBox {

}

If you open MyTextClass constructor definition in ildasm you will notice an instruction calling BaseClass constructor i.e. TextBox::.ctor() This must be replaced with NewTextBox reference.i.e. NewTextBox::.ctor()

try this:

injectionTextBoxRef: Type reference of the class we are replacing with.

textBoxRef: Type reference of the base class of the class you are replacing.

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);
                            }
                        }
                    }
                }
            }
        }


标签: mono.cecil