Can I use reflection to find aspects produced by multicast? - postsharp

I have a case where an aspect CanBeDependedUpon on class A is multicast to the properties of class A. However when inspecting class A from aspect DependsOn, I do not find CanBeDependedUpon on the properties of Y. Is this correct PostSharp behavior?
[CanBeDependedUpon]
class A
{
public bool Foo
{
get;
set;
}
[DependsOn("Foo")]
public bool Bar
{
get;
set;
}
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property, AllowMultiple = true)]
[MulticastAttributeUsage(MulticastTargets.Class | MulticastTargets.Struct | MulticastTargets.Property, PersistMetaData = true, AllowMultiple = true)]
class CanBeDependedUpon : Aspect
{
}
class DependsOn : Aspect
{
private string _target;
public DependsOn(string target)
{
_target = target;
}
public override bool CompileTimeValidate(object target)
{
//validate that the target property exists and is annotated with X.
return base.CompileTimeValidate(target);
}
}

By default, PostSharp removes the attribute once the aspect has been applied to your code. You can explicitly instruct PostSharp to retain the attributes if you want to look them up using reflection.
For this, you need to apply MulticastAttributeUsage attribute to your class and set PersistMetaData to true.
[MulticastAttributeUsage( MulticastTargets.Class, PersistMetaData = true )]
This use case is documented here: http://doc.postsharp.net/multicast-reflection

Related

If a type satisfies the implementation of an interface should it 'implement' it?

I have this interface
public interface IWeighted {
int Weight { get; }
}
and this attribute
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
public class WeightAttribute : Attribute {
private readonly int m_Weight;
public int Weight => m_Weight;
public WeightAttribute(int weight = 1) {
m_Weight = weight;
}
}
Should WeightAttribute implement IWeighted as it exactly matches the contract declared within IWeighted, or should it not seeing as WeightAttribute is an attribute (intended for use on enum members alone) and as such should not be target to selection itself?

Can I insert backing fields for properties with a specific implementation?

I'm trying to create an attribute with PostSharp to implement specific backing fields of properties. However I did not find any helpful answers in the documentation, official examples or here on SO.
Here's an example of what I'm trying to do:
[WrappedProperty]
public int MyProperty { get; set; }
will compile to
private WrapperClass<int> _generatedBackingField_myProperty;
public int MyProperty
{
get => _generatedBackingField_myProperty.Value;
set => _generatedBackingField_myProperty.Value = value;
}
Is there any way to achieve this with PostSharp?
I found the answer, you can use LocationInterceptionAspect to intercept properties.
So the code would look like this:
[PSerializable]
public class WrappedProperty : LocationInterceptionAspect
{
private WrapperClass<object> _backingField;
public override void OnGetValue(LocationInterceptionArgs args)
{
InitBackingField();
args.Value = _backingField.Value;
}
public override void OnSetValue(LocationInterceptionArgs args)
{
InitBackingField();
_backingField.Value = args.Value;
}
}

Adding Aspects to Derived Classes

I had wrote an aspect that works fine, but only on base classes, on derived classes do nothing.
Please, what I am missing?
The code is as follow
public interface INotifyOnChange : INotifyPropertyChanged
{
void OnPropertyChanged(string propertyName);
}
[Serializable]
[AspectConfiguration(AspectPriority = 10)]
[IntroduceInterface(typeof(INotifyOnChange), OverrideAction = InterfaceOverrideAction.Ignore, AncestorOverrideAction = InterfaceOverrideAction.Ignore)]
[MulticastAttributeUsage(MulticastTargets.Class, Inheritance = MulticastInheritance.Strict, AllowMultiple = false)]
public sealed class NotifyPropertiesOnChange : InstanceLevelAspect, INotifyOnChange
{
[IntroduceMember(Visibility = Visibility.Family, IsVirtual = true, OverrideAction = MemberOverrideAction.Ignore)]
public void OnPropertyChanged(string propertyName)
=> PropertyChanged?.Invoke(Instance, new PropertyChangedEventArgs(propertyName));
[IntroduceMember(OverrideAction = MemberOverrideAction.Ignore)]
public event PropertyChangedEventHandler PropertyChanged;
[OnLocationSetValueAdvice, MulticastPointcut(Targets = MulticastTargets.Property, Attributes = MulticastAttributes.Public | MulticastAttributes.Instance)]
public void OnSetValue(LocationInterceptionArgs args)
{
if (args.Value == args.GetCurrentValue())
return;
args.ProceedSetValue();
var notifyOnChange = args.Instance as INotifyOnChange;
notifyOnChange?.OnPropertyChanged(args.Location.PropertyInfo.Name);
}
}
I had also tested with Inheritance = MulticastInheritance.Multicast without success.
However if I have a base class like the one here below it works
[NotifyOnChange]
public class EuroRate
{
public string Currency { get; set; }
public decimal Rate { get; set; }
public DateTime Date { get; set; }
}
but if try on a derived class (removing the aspect from the base class of course) it don't works
public class EuroRate
{
public string Currency { get; set; }
public decimal Rate { get; set; }
public DateTime Date { get; set; }
}
[NotifyPropertiesOnChange]
public class RateModel : EuroRate
{
}
An aspect can only alter the declaration on which it is applied. In case of your aspect (TypeLevelAspect) this means that when applied on RateModel class it can only apply advices on properties declared directly by this class. Properties declared by the base will not be transformed (as you would need to transform the base itself).
In this case, the best option is to rely on the multicast inheritance itself, i.e. apply the aspect on the base class. This would mean that you need to work with the fact that the aspect is applied separately on each class and develop a mechanism for communication between these aspects.
Performance concerns
You might have noticed that this would cause multiple instances of the aspect to exist for a single instance of the target class (depending on levels of inheritance).
You can optimize this by using combination of an instance-level aspect that introduces the OnPropertyChanged method, the event and the interface. This aspect would not be applied directly but through IAspectProvider by the main aspect that would be mere TypeLevelAspect.
Ad your Multicast Inheritance note (see the documentation):
For TypeLevelAspect applied on type [MulticastInheritance.Strict] and [MulticastInheritance.Multicast] are essentially the same.
The reason is that multicast inheritance also takes into account the declaration on which it was multicasted (inherits the multicast itself); i.e. if you apply method level aspect on a type, multicast inheritance will cause derived classes to inherit the aspect for all of its methods.
On the other the strict inheritance will cause only the applied aspect to be inherited, i.e. only overriding methods will have the aspect.

Dynamic way to Generate EntityTypeConfiguration : The type 'TResult' must be a non-nullable value type

I was thinking to generate EntityTypeConfiguration dynamically from run time and i don't want any EF dependency in Models[That is why i avoid Data Annotation].
So I declare a custom attribute(or can be any configuration file later on)
[AttributeUsage(AttributeTargets.Property, AllowMultiple=true )]
public class PersistableMemberAttribute : Attribute
{
public bool Iskey;
public bool IsRequired;
public bool IsIgnored;
public bool IsMany;
public string HasForeignKey;
public bool PropertyIsRequired;
public bool PropertyIsOptional;
}
And here is one of my Models is look like:
public class Blog
{
[PersistableMember(Iskey=true)]
public Guid BlogId { get; set; }
[PersistableMember(PropertyIsRequired = true)]
public string Name { get; set; }
public string Url { get; set; }
[PersistableMember(IsIgnored=true)]
public int Rating { get; set; }
[PersistableMember(IsMany =true)]
public ICollection<Post> Posts { get; set; }
}
Now I am going to write a generic EntityTypeConfiguration , which will create the configuration dynamically on run time based on the attribute values :
public class GenericEntityConfiguration<T> : EntityTypeConfiguration<T> where T : class
{
public GenericEntityConfiguration()
{
var members = typeof(T).GetProperties();
if (null != members)
{
foreach (var property in members)
{
var attrb= property.GetCustomAttributes(typeof( PersistableMemberAttribute ),false).OfType<PersistableMemberAttribute>();
if (attrb != null && attrb.Count() > 0)
{
foreach (var memberAttributute in attrb)
{
if (memberAttributute.Iskey || memberAttributute.IsIgnored)
{
var entityMethod = this.GetType().GetMethod("Setkey");
entityMethod.MakeGenericMethod(property.PropertyType)
.Invoke(this, new object[] { property, memberAttributute });
}
if (memberAttributute.IsRequired)
{
var entityMethod = this.GetType().GetMethod("SetRequired");
entityMethod.MakeGenericMethod(property.PropertyType)
.Invoke(this, new object[] { property, memberAttributute });
}
if (memberAttributute.PropertyIsRequired || memberAttributute.PropertyIsOptional)
{
var entityMethod = this.GetType().GetMethod("SetPropertyConfiguration");
entityMethod.MakeGenericMethod(property.PropertyType)
.Invoke(this, new object[] { property, memberAttributute });
}
}
}
}
}
}
public void SetPropertyConfiguration<TResult>(PropertyInfo propertyInfo, PersistableMemberAttribute attribute)
{
var functorParam = Expression.Parameter(typeof(T));
var lambda = Expression.Lambda(
Expression.Property(functorParam, propertyInfo)
, functorParam);
if (attribute.PropertyIsRequired)
{
this.Property<TResult>((Expression<Func<T, TResult>>)lambda).IsRequired();
}
if (attribute.PropertyIsOptional)
{
this.Property<TResult>((Expression<Func<T, TResult>>)lambda).IsOptional();
}
}
public void Setkey<TResult>(PropertyInfo propertyInfo, PersistableMemberAttribute attribute)
{
var functorParam = Expression.Parameter(typeof(T));
var lambda = Expression.Lambda(
Expression.Property(functorParam, propertyInfo)
, functorParam);
if (attribute.Iskey)
{
this.HasKey<TResult>((Expression<Func<T,TResult>>)lambda);
}
if (attribute.IsIgnored)
{
this.Ignore<TResult>((Expression<Func<T, TResult>>)lambda);
}
}
public void SetRequired<TResult>(PropertyInfo propertyInfo, PersistableMemberAttribute attribute) where TResult : class
{
var functorParam = Expression.Parameter(typeof(T));
var lambda = Expression.Lambda(
Expression.Property(functorParam, propertyInfo)
, functorParam);
if (attribute.IsRequired)
{
this.HasRequired<TResult>((Expression<Func<T, TResult>>)lambda);
}
}
}
But i got the compilation error of
Error 1 The type 'TResult' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'System.Data.Entity.ModelConfiguration.Configuration.StructuralTypeConfiguration.Property(System.Linq.Expressions.Expression>)' D:\R&D\UpdateStorePOC\UpdateStorePOC\Data\GenericEntityConfiguration.cs 63 17 UpdateStorePOC
which for these two statements:
this.Property<TResult>((Expression<Func<T, TResult>>)lambda).IsRequired();
this.Property<TResult>((Expression<Func<T, TResult>>)lambda).IsOptional();
that means that I need to put a constraint on my method to restrict it to a value type. In C#, this is done with the ‘struct’ keyword.
public void SetPropertyConfiguration<TResult>(PropertyInfo propertyInfo, PersistableMemberAttribute attribute) Where TResult : struct
But Its not the solution since my property type can be a class e.g string or int, bool double, etc . So it is not at all clear that I can send them into this method. Please help me to solve this issue whether there is any other way to do it.
I don't want any EF dependency in models.
With fluent mapping you're almost there and you won't come any closer. Your attributes, even though intended to be moved to a configuration file, don't make your model any more free of any EF footprint.1 Worse, they only add a second mapping layer (if you like) between your model and EF's mapping. I only see drawbacks:
You still have to maintain meta data for your model, probably not any less than regular fluent mapping and (probably) in awkward manually edited XML without compile-time checking.
You will keep expanding your code to cover cases that EF's mapping covers but yours doesn't yet.2 So it's a waste of energy: in the end you'll basically have rewritten EF's mapping methods.
You'll have to keep your fingers crossed when you want to upgrade EF.
With bugs/problems you're on your own: hard to get support from the community.
So my answer to your question help me to solve this issue would be: use fluent mapping out of the box. Keep it simple.
1 For example, you would still have to use the virtual modifier to enable proxies for lazy loading.
2 Like support for inheritance, unmapped foreign keys, max length, db data type, ... this could go on for a while.

MEF Metadata from the exported parts

I'm looking to use MEF for a plugin system for an application I'm building. Each component I want to have an identifier on (a GUID) which I want to be able to look up against. But this ID is also something that is useful when working with the exported part.
Is there a way that I can have a Metadata attribute which contains the ID as well as a property (or method) on the exported part, short of having developers fill it out twice or use reflection to find it from the attribute?
It's likely to be a mixture of a MEF metadata attribute, and an abstract base class. I would define my plugin contract as something like:
public interface IPluginMetadata
{
Guid PluginId { get; }
}
public interface IPlugin : IPluginMetadata
{
void Initialise();
}
I've enforced that the IPlugin interface also inherits our metadata contract IPluginMetadata. Next, we can create a custom export attribute:
[AttributeUsage(AttributeTargets.Class, Inherit = true), MetadataAttribute]
public class ExportPluginAttribute : ExportAttribute, IPluginMetadata
{
public ExportPluginAttribute(string pluginId) : base(typeof(IPlugin))
{
if (string.IsNullOrEmpty(pluginId))
throw new ArgumentException("'pluginId' is required.", "pluginId");
PluginId = new Guid(pluginId);
}
public Guid PluginId { get; private set; }
}
You don't need to decorate the export attribute with the metadata contract IPluginMetadata, as MEF will project the properties anyway, but I prefer to do so, so if I do introduce changes to my metadata contract, then my export attribute should be updated too. No harm, no foul.
Once we've done this, we can define an abstract base class from which to implement our plugin contract:
public abstract class PluginBase : IPlugin
{
protected PluginBase()
{
var attr = GetType()
.GetCustomAttributes(typeof(ExportPluginAttribute), true)
.Cast<ExportPluginAttribute>()
.SingleOrDefault();
PluginId = (attr == null) ? Guid.Empty : attr.PluginId;
}
public virtual Guid PluginId { get; private set; }
public abstract void Initialise();
}
We can then grab the custom attribute through the abstract class's constructor, and apply the property accordingly. That we can do:
public IPlugin GetPlugin(Guid id)
{
var plugin = container
.GetExports<IPlugin, IPluginMetadata>()
.Where(p => p.Metadata.PluginId == id)
.Select(p => p.Value)
.FirstOrDefault();
return plugin;
}
And also:
[ExportPlugin("BE112EA1-1AA1-4B92-934A-9EA8B90D622C")]
public class MyPlugin : PluginBase
{
public override Initialise()
{
Console.WriteLine(PluginId);
}
}
We can see that out PluginId is exposed both through exported metadata, as well as a property of our plugin.
That code is all untested, but I hope it pushes you in the right direction.
Put the GUID in a constant, and use it for both a property and the metadata:
[Export(typeof(IFoo))]
[ExportMetadata("GUID", _guid)]
public class Foo : IFoo
{
private const string _guid = "abc";
public string Guid { get { return _guid; } }
}
Note that you can't use the Guid type instead of string, as that is not permitted by the const keyword.