Today I upgraded to PostSharp 3. After some messing around with referencing the correct DLLs in my projects I compile and all seems fine, until I get a runtime exception. An aspect which has been working perfectly fine in PostSharp 2.1 now behaves differently.
It's a generic aspect applied with help of IAspectProvider
. Full source can be found on GitHub.
public IEnumerable<AspectInstance> ProvideAspects( object targetElement )
{
Type targetType = (Type)targetElement;
Type genericAspect = typeof( ViewModelAspect<,> ).MakeGenericType( _propertiesEnumType, _commandsEnumType );
yield return new AspectInstance( targetType, Activator.CreateInstance( genericAspect ) as IAspect );
}
What seems to happen is the aspect with wrong generic parameters is applied to my type. When I use dotPeek to look at the post-compiled code I see a newly introduced generic field with generic parameters which are meant to be applied on a different type. In fact, all types with the aspect applied to share the same generic parameters (and thus only one is correct).
This was working correctly before, did anything relating to IAspectProvider
change in PostSharp 3 that I should think about?
For debugging purposes I already checked whether _propertiesEnumType
and _commandsEnumType
are set correctly at build time, and they are, thus I think something must go wrong afterwards; perhaps the created aspects being applied to the wrong instances?
Below you can see the decompiled code where PostSharp seems to be doing something wrong. The correct aspect seems to be introduced, however the property I am introducing is exposed as a different (wrong) type. Notice the ViewModel.Main
as parameter of the aspect, contrasted with the ViewModel.ActivityOverview
as parameter for the CommandFactory
, which should be ViewModel.Main
as well.
[NonSerialized]
private ViewModelAspect<Laevo.ViewModel.Main.Binding.Properties, Laevo.ViewModel.Main.Binding.Commands> \u003C\u003Ez__aspect35;
private CommandFactory<Laevo.ViewModel.ActivityOverview.Binding.Commands> CommandFactory
{
get
{
return ((ViewModelAspect<Laevo.ViewModel.ActivityOverview.Binding.Properties, Laevo.ViewModel.ActivityOverview.Binding.Commands>) this.\u003C\u003Ez__aspect35).CommandFactory;
}
}
I turned out to be a bug in the new version. The updated version on NuGet fixes the issue.
Before the fix was released, I temporarily worked around it by introducing non-generic members instead and relying on reflection a bit more at run time.
[IntroduceMember( Visibility = Visibility.Private )]
//public CommandFactory<TCommands> CommandFactory
public object CommandFactory
{
get { return _commandFactory; }
private set { _commandFactory = value; }
}
Notice that the incorrect conversion (it should be Laevo.ViewModel.Main
in this case) is still generated by PostSharp:
private object CommandFactory
{
get
{
return ((ViewModelAspect<Laevo.ViewModel.ActivityOverview.Binding.Properties, Laevo.ViewModel.ActivityOverview.Binding.Commands>) this.\u003C\u003Ez__aspect35).CommandFactory;
}
}
However, since the correct generic aspect is created, I can cast to the correct type at run time. Everything works ... the code just got a whole lot messier (and probably slower due to relying on reflection more).