Добавление вызова к обобщенному c методу в открытом обобщенном c в Fody - PullRequest
0 голосов
/ 31 марта 2020

Я пытаюсь соткать вызов метода, используя Fody, чтобы исправить проблему, которая вызывает некоторую несовместимость между ReactiveUI и PropertyChanged.Fody

Теперь реализация работает отлично для всех моих тестовых случаев, кроме одного - переплетения это открытый тип c.

Вот важные биты:

  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);
Генерация 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 (не уверен, что это правильно - можно найти в другом сообщении по пути)

        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
            }

Запустив его, он отлично работает для всего, кроме open generi c type

Когда я смотрю на сгенерированный код в 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() но я не могу понять, что это, ошибка при запуске кода на закрытом экземпляре generi c (например, MyReactiveObject<string>):

System.TypeLoadException: не удалось загрузить тип 'Weavers.Tests.MyReactiveObject`1' из сборки 'Weavers.Tests, версия = 1.0.0.0, культура = нейтральная, PublicKeyToken = null'.

1 Ответ

0 голосов
/ 31 марта 2020

Решено - открытый тип generi c, подобный этому, должен быть «закрыт» с использованием параметров типа open generi c. (Что имеет смысл, когда вы думаете об этом)


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