在 Fody 的开放泛型中添加对泛型方法的调用
Adding a call to a generic method within an open generic in Fody
我正在尝试使用 Fody 编织一个方法调用来修复导致 ReactiveUI 和 PropertyChanged.Fody
之间不兼容的问题
现在,该实现对我的所有测试用例都适用,除了一个 - 将其编织成一个开放的通用类型。
以下是重要的部分:
- 创建方法参考
//get the method to call
var reactiveExRaiseMethod = FindTypeDefinition("ReactiveUI.IReactiveObjectExtensions").GetMethods().Single(x => x.Name == "RaisePropertyChanged");
var reactiveExRaiseMethodRef = ModuleDefinition.ImportReference(reactiveExRaiseMethod);
var raiseMethod = reactiveExRaiseMethodRef.MakeGenericMethod(type);
- 正在生成 IL
var il = method.Body.GetILProcessor();
il.Emit(OpCodes.Nop);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, raiseMethod);
il.Emit(OpCodes.Nop);
il.Emit(OpCodes.Ret);
MakeGenericMethod
(不确定这是否正确 - 一路上在另一个 post 上找到)
public static MethodReference MakeGenericMethod(this MethodReference self, params TypeReference[] arguments)
{
if (self.GenericParameters.Count != arguments.Length)
throw new ArgumentException();
var instance = new GenericInstanceMethod(self);
foreach (var argument in arguments)
instance.GenericArguments.Add(argument);
return instance;
}
- 调用此代码
public class ReactiveObjectPropertyChangeFix : BaseModuleWeaver
{
public override void Execute()
{
foreach (var type in ModuleDefinition.Types)
{
VisitType(type); //this subsequently passes this reference to the code shown above
}
运行 除了开放泛型类型
,它对所有东西都适用
当我在 ILSpy 中查看生成的代码时,我看到它生成了这个:
public class MyReactiveObject<T> : ReactiveObject
{
protected void OnPropertyChanged(string propertyName)
{
((MyReactiveObject<>)this).RaisePropertyChanged(propertyName);
}
}
而不是这个(取自传递的测试用例对象):
public class MyReactiveObject : ReactiveObject
{
protected void OnPropertyChanged(string propertyName)
{
this.RaisePropertyChanged(propertyName);
}
}
我知道 MakeGenericReference()
创建的引用有问题,但我无法弄清楚它是什么,运行 封闭通用实例上的代码错误(例如MyReactiveObject<string>
) 是:
System.TypeLoadException : Could not load type 'Weavers.Tests.MyReactiveObject`1' from assembly 'Weavers.Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
已解决 - 像这样的开放泛型类型需要 "closed" 使用开放泛型类型参数。 (当你想到它时,这是完全有道理的)
public static MethodReference MakeGenericMethod(this MethodReference self, params TypeReference[] arguments)
{
if (self.GenericParameters.Count != arguments.Length)
throw new ArgumentException();
var instance = new GenericInstanceMethod(self);
foreach (var argument in arguments.Select(MakeTypeReference).ToArray())
instance.GenericArguments.Add(argument);
return instance;
TypeReference MakeTypeReference(TypeReference t)
{
if (t.HasGenericParameters && !t.IsGenericInstance)
{
//this is the magic here - if we are passed an open generic then "close" it with the it's own type parameters
return t.MakeGenericType(t.GenericParameters.Select(x => (TypeReference)x).ToArray());
}
return t;
}
}
我正在尝试使用 Fody 编织一个方法调用来修复导致 ReactiveUI 和 PropertyChanged.Fody
之间不兼容的问题现在,该实现对我的所有测试用例都适用,除了一个 - 将其编织成一个开放的通用类型。
以下是重要的部分:
- 创建方法参考
//get the method to call
var reactiveExRaiseMethod = FindTypeDefinition("ReactiveUI.IReactiveObjectExtensions").GetMethods().Single(x => x.Name == "RaisePropertyChanged");
var reactiveExRaiseMethodRef = ModuleDefinition.ImportReference(reactiveExRaiseMethod);
var raiseMethod = reactiveExRaiseMethodRef.MakeGenericMethod(type);
- 正在生成 IL
var il = method.Body.GetILProcessor();
il.Emit(OpCodes.Nop);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Call, raiseMethod);
il.Emit(OpCodes.Nop);
il.Emit(OpCodes.Ret);
MakeGenericMethod
(不确定这是否正确 - 一路上在另一个 post 上找到)
public static MethodReference MakeGenericMethod(this MethodReference self, params TypeReference[] arguments)
{
if (self.GenericParameters.Count != arguments.Length)
throw new ArgumentException();
var instance = new GenericInstanceMethod(self);
foreach (var argument in arguments)
instance.GenericArguments.Add(argument);
return instance;
}
- 调用此代码
public class ReactiveObjectPropertyChangeFix : BaseModuleWeaver
{
public override void Execute()
{
foreach (var type in ModuleDefinition.Types)
{
VisitType(type); //this subsequently passes this reference to the code shown above
}
运行 除了开放泛型类型
,它对所有东西都适用当我在 ILSpy 中查看生成的代码时,我看到它生成了这个:
public class MyReactiveObject<T> : ReactiveObject
{
protected void OnPropertyChanged(string propertyName)
{
((MyReactiveObject<>)this).RaisePropertyChanged(propertyName);
}
}
而不是这个(取自传递的测试用例对象):
public class MyReactiveObject : ReactiveObject
{
protected void OnPropertyChanged(string propertyName)
{
this.RaisePropertyChanged(propertyName);
}
}
我知道 MakeGenericReference()
创建的引用有问题,但我无法弄清楚它是什么,运行 封闭通用实例上的代码错误(例如MyReactiveObject<string>
) 是:
System.TypeLoadException : Could not load type 'Weavers.Tests.MyReactiveObject`1' from assembly 'Weavers.Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
已解决 - 像这样的开放泛型类型需要 "closed" 使用开放泛型类型参数。 (当你想到它时,这是完全有道理的)
public static MethodReference MakeGenericMethod(this MethodReference self, params TypeReference[] arguments)
{
if (self.GenericParameters.Count != arguments.Length)
throw new ArgumentException();
var instance = new GenericInstanceMethod(self);
foreach (var argument in arguments.Select(MakeTypeReference).ToArray())
instance.GenericArguments.Add(argument);
return instance;
TypeReference MakeTypeReference(TypeReference t)
{
if (t.HasGenericParameters && !t.IsGenericInstance)
{
//this is the magic here - if we are passed an open generic then "close" it with the it's own type parameters
return t.MakeGenericType(t.GenericParameters.Select(x => (TypeReference)x).ToArray());
}
return t;
}
}