2016-08-22 100 views
0

如何使用Mono Cecil生成必要的IL代码以调用System.Collections.Generic.EqualityComparer<T>.get_Default方法?与Cecil呼叫EqualityComparer.Default

我试过类似的变体,但得到了各种各样的错误,从PEVerify不能解析令牌,超过Cecil抱怨某件事是从另一个模块并需要导入到Cecil本身的ArgumentOutOfRangeException。

泛型类型参数来自我在这里处理的属性的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是包含一个名为TestClass类型,包含方法TestMethod一个dll。

之前我添加了调用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