EqualityComparer打电话.默认是Cecil

本文关键字:Cecil 默认 打电话 EqualityComparer | 更新日期: 2023-09-27 18:03:27

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

我尝试过类似的变体,但得到了各种各样的错误,从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));

我需要什么代码?

EqualityComparer打电话.默认是Cecil

应该可以了

 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