与 Cecil 通话 EqualityComparer.Default
Call EqualityComparer.Default with Cecil
如何生成必要的 IL 代码以使用 Mono Cecil 调用 System.Collections.Generic.EqualityComparer<T>.get_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));
我需要什么代码?
来自其他模块的通用实例总是很棘手。
这应该有效
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
的类型的 dll,其中包含方法 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
如何生成必要的 IL 代码以使用 Mono Cecil 调用 System.Collections.Generic.EqualityComparer<T>.get_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));
我需要什么代码?
来自其他模块的通用实例总是很棘手。
这应该有效
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
的类型的 dll,其中包含方法 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