I'm attempting to weave a method call using Fody to fix an issue that causes some incompatibility between ReactiveUI and PropertyChanged.Fody
Now the implementation works just fine for all of my test cases except one - weaving it into an open generic type.
Here are the important bits:
- Creating the method reference
//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);
- Generating the 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
(not sure if this is correct - found on another post along the way)
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;
}
- Calling this code
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
}
Running this it works fine for everything except the open generic type
When i look at the generated code in ILSpy i see that it generates this:
public class MyReactiveObject<T> : ReactiveObject
{
protected void OnPropertyChanged(string propertyName)
{
((MyReactiveObject<>)this).RaisePropertyChanged(propertyName);
}
}
Instead of this (taken from the passing testcase object):
public class MyReactiveObject : ReactiveObject
{
protected void OnPropertyChanged(string propertyName)
{
this.RaisePropertyChanged(propertyName);
}
}
I know that there is something wrong with the reference created by MakeGenericReference()
but I can't work out what it is, the error upon running the code on a closed generic instance (e.g. MyReactiveObject<string>
) is:
System.TypeLoadException : Could not load type 'Weavers.Tests.MyReactiveObject`1' from assembly 'Weavers.Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.