在 Fody 的开放泛型中添加对泛型方法的调用

Adding a call to a generic method within an open generic in Fody

我正在尝试使用 Fody 编织一个方法调用来修复导致 ReactiveUI 和 PropertyChanged.Fody

之间不兼容的问题

现在,该实现对我的所有测试用例都适用,除了一个 - 将其编织成一个开放的通用类型。

以下是重要的部分:

  1. 创建方法参考


            //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);
  1. 正在生成 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);

  1. 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;
        }
  1. 调用此代码
  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;
            }
        }