2016-08-22 97 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