How to enter a call in System.Object.Equals with Mono.Cecil?

Using Mono.Cecil I want to rewrite the following property:

public string FirstName
{
    get { return _FirstName; }
    set
    {
        _FirstName = value;
    }
}

:

public string FirstName
{
    get { return _FirstName; }
    set
    {
        if (System.Object.Equals(_FirstName, value))
        {
            return;
        }
        _FirstName = value;
    }
}

This is just a fragment of what will be texted, but it is there that I have a problem.

Using Reflector, I see that the following code overwrites the property as needed, except for calling System.Object.Equals (). If you expect IL code:

call bool [mscorlib]System.Object::Equals(object, object)

but it is written as:

call instance void RewriteSharp.Person::.ctor()

Code to invoke the call to System.Object.Equals:

setMethodWriter.InsertBefore(
    firstExistingInstruction, 
    setMethodWriter.Create(OpCodes.Call, objectEqualsMethodReference));

Method used to initialize objectEqualsMethodReference:

private static MethodReference GetSystemObjectEqualsMethodReference(
    AssemblyDefinition assembly
)
{

    var typeReference = assembly.MainModule.GetTypeReferences()
        .Single(t => t.FullName == "System.Object");

    var typeDefinition = typeReference.Resolve();

    var methodDefinition = typeDefinition.Methods.Single(
                            m => m.Name == "Equals"
                                && m.Parameters.Count == 2
                                && m.Parameters[0].ParameterType.Name == "Object"
                                && m.Parameters[1].ParameterType.Name == "Object"
    );

    return methodDefinition;
}

It seems to me that setMethodWriter.Create () or GetSystemObjectEqualsMethodReference () is incorrect, and no debugging has solved the problem.

The property being written and the code for overwriting the property have the same target platform. 3.5 and 4.0 both do not work.

https://github.com/jbevain/cecil Mono.Cecil.

using Mono.Cecil;
using Mono.Cecil.Cil;
using System;
using System.Linq;

namespace RewriteNotifyPropertyChanged
{
class Program
{
static void Main(string[] args)
{
    var rewrite = "..\\RewriteSharp.dll";
    var rewritten  = "..\\RewritenSharp.dll";

    var typeName = "Person";
    var propertyName = "FirstName";

    var assembly = AssemblyDefinition.ReadAssembly(rewrite);
    var typeDefinition = assembly.MainModule.Types.Single(t => t.Name == typeName);
    var propertyDefintion = typeDefinition.Properties
        .Single(p => p.Name == propertyName);

    var setMethodWriter = propertyDefintion.SetMethod.Body.GetILProcessor();
    var backingFieldReference = GetBackingFieldReference(typeDefinition, propertyName);
    var objectEqualsMethodReference = GetSystemObjectEqualsMethodReference(assembly);
    var firstExistingInstruction = setMethodWriter.Body.Instructions[0];

    setMethodWriter.InsertBefore(
        firstExistingInstruction, 
        setMethodWriter.Create(OpCodes.Ldarg_0));

    setMethodWriter.InsertBefore(
        firstExistingInstruction, 
        setMethodWriter.Create(OpCodes.Ldfld, backingFieldReference));

    setMethodWriter.InsertBefore(
        firstExistingInstruction, 
        setMethodWriter.Create(OpCodes.Ldarg_1));

    setMethodWriter.InsertBefore(
        firstExistingInstruction, 
        setMethodWriter.Create(OpCodes.Call, objectEqualsMethodReference));

    setMethodWriter.InsertBefore(
        firstExistingInstruction, 
        setMethodWriter.Create(OpCodes.Brfalse_S, firstExistingInstruction));

    setMethodWriter.InsertBefore(
        firstExistingInstruction, 
        setMethodWriter.Create(OpCodes.Ret));

    assembly.Write(rewritten, new WriterParameters { WriteSymbols = true });

    Console.WriteLine("Done.");
    Console.ReadKey();
}

private static MethodReference GetSystemObjectEqualsMethodReference(
    AssemblyDefinition assembly
)
{

    var typeReference = assembly.MainModule.GetTypeReferences()
        .Single(t => t.FullName == "System.Object");

    var typeDefinition = typeReference.Resolve();

    var methodDefinition = typeDefinition.Methods.Single(
                            m => m.Name == "Equals"
                                && m.Parameters.Count == 2
                                && m.Parameters[0].ParameterType.Name == "Object"
                                && m.Parameters[1].ParameterType.Name == "Object"
    );

    return methodDefinition;
}

private static FieldReference GetBackingFieldReference(
    TypeDefinition typeDefinition, 
    string propertyName
)
{
    var fieldName = "_" + propertyName;
    var fieldReference = typeDefinition.Fields.Single(f => f.Name == fieldName);

    return fieldReference;
}
}
}
+3
2

Cecil, System.Reflection, , . , MethodDefinition . . , importing .

, GetSystemObjectEqualsMethodReference , corlib, :

:

var objectEqualsMethodReference = GetSystemObjectEqualsMethodReference(assembly);

:

var objectEqualsMethodReference = assembly.MainModule.Import (GetSystemObjectEqualsMethodReference(assembly));

IL .

, , :

private static MethodReference GetSystemObjectEqualsMethodReference(AssemblyDefinition assembly)
{
    var typeReference = assembly.MainModule.GetTypeReferences()
        .Single(t => t.FullName == "System.Object");

    var typeDefinition = typeReference.Resolve();

    var methodDefinition = typeDefinition.Methods.Single(
                            m => m.Name == "Equals"
                                && m.Parameters.Count == 2
                                && m.Parameters[0].ParameterType.Name == "Object"
                                && m.Parameters[1].ParameterType.Name == "Object"
    );

    return methodDefinition;
}

:

private static MethodReference GetSystemObjectEqualsMethodReference(AssemblyDefinition assembly)
{
    var @object = assembly.MainModule.TypeSystem.Object.Resolve ();

    return @object.Methods.Single(
        m => m.Name == "Equals"
            && m.Parameters.Count == 2
            && m.Parameters[0].ParameterType.MetadataType == MetadataType.Object
            && m.Parameters[1].ParameterType.MetadataType == MetadataType.Object);
}

assembly.Write(rewritten, new WriterParameters { WriteSymbols = true });

, new ReaderParameters { ReadSymbols = true } .

+6

KindOfMagic codeplex.

, - Object.Equals(), .

http://kindofmagic.codeplex.com

+1

Source: https://habr.com/ru/post/1778870/


All Articles