2016-08-22 3 views
0

Как я могу сгенерировать необходимый код IL для вызова метода System.Collections.Generic.EqualityComparer<T>.get_Default с Mono Cecil?Вызов EqualityComparer.Default с Cecil

Я пробовал подобные варианты, но получал различные ошибки: от PEVerify, неспособного разрешить токен, а Сесил жаловался, что что-то из другого модуля и нужно импортировать, в ArgumentOutOfRangeException из самого Cecil.

Общий аргумент типа относится к PropertyType свойства, которое я обрабатываю здесь.

PropertyDefinition propertyDef = ...; 
var equalityComparer = typeDef.Module.ImportReference(typeof(System.Collections.Generic.EqualityComparer<>)); 
var equalityComparerInst = equalityComparer.MakeGenericInstanceType(propDef.PropertyType); 
var getDefaultMethod = equalityComparerInst.Resolve().Methods.First(m => m.Name == "get_Default"); 
var getDefaultMethodRef = typeDef.Module.ImportReference(getDefaultMethod, getDefaultMethod); 
il.Append(il.Create(OpCodes.Call, getDefaultMethodRef)); 

Какой код необходим для этого?

Общие экземпляры из других модулей всегда сложны.

ответ

1

Это должно работать

private static void CallEqualityComparerDefault() 
{ 
    string assemblyPath = $"{Environment.CurrentDirectory}\\ClassLibrary1.dll"; 
    var mainModule = AssemblyDefinition.ReadAssembly(assemblyPath).MainModule; 

    var methodDef = mainModule.Types.First(
     type => type.Name == "TestClass").Methods.Single(m => m.Name == "TestMethod"); 

    var eq = mainModule.Import(typeof(EqualityComparer<>)); 
    var obj = mainModule.Import(typeof(object)); 
    var genericEq = new GenericInstanceType(eq); 
    genericEq.GenericArguments.Add(obj); 
    var importedGenericEq = mainModule.Import(genericEq); 
    var defaultMethodDef = importedGenericEq.Resolve().Methods.Single(m => m.Name == "get_Default"); 
    var methodRef = mainModule.Import(defaultMethodDef); 
    methodRef.DeclaringType = importedGenericEq; 

    var ilProcessor = methodDef.Body.GetILProcessor(); 
    ilProcessor.InsertBefore(
     ilProcessor.Body.Instructions.First(), 
     Instruction.Create(OpCodes.Callvirt, methodRef)); 
    methodDef.Body.OptimizeMacros(); 

    mainModule.Write(assemblyPath + ".new.dll"); 
} 

ClassLibrary является DLL, который содержит тип, называемый TestClass, который содержит метод TestMethod.

Перед тем, как добавить вызов EqualityComparer<>.Default тело метода выглядит следующим образом:

IL_0000: nop 
IL_0001: ret 

и после:

IL_0000: callvirt class [mscorlib]System.Collections.Generic.EqualityComparer`1<!0> class [mscorlib]System.Collections.Generic.EqualityComparer`1<object>::get_Default() 
IL_0005: nop 
IL_0006: ret 
+0

Отлично, спасибо! Я почти пропустил строку 'methodRef.DeclaringType = importedGenericEq;', но, поскольку она все еще не работала для меня, я тоже нашел эту строку. – ygoe

Смежные вопросы