【问题标题】:Adding a call to a generic method within an open generic in Fody在 Fody 的开放泛型中添加对泛型方法的调用
【发布时间】:2020-03-31 03:47:05
【问题描述】:

我正在尝试使用 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(不确定这是否正确 - 在另一篇文章中找到)

        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&lt;string&gt;)上运行代码时的错误是:

System.TypeLoadException:无法从程序集“Weavers.Tests,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null”加载类型“Weavers.Tests.MyReactiveObject`1”。

【问题讨论】:

    标签: c# mono.cecil fody


    【解决方案1】:

    解决了 - 像这样的开放泛型类型需要使用开放泛型类型参数“关闭”。 (仔细想想,这完全有道理)

    
            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;
                }
            }
    

    【讨论】:

      猜你喜欢
      • 2011-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-11
      • 1970-01-01
      • 2011-04-23
      相关资源
      最近更新 更多