[PostSharp] Ease the creation of configuration sections - Update
By Michael DELVA on Tuesday 7 December 2010, 09:56 - C# - Permalink
TweetIn the previous article, we saw how to use PostSharp to help us to use the configuration sections, with the use of two aspects. In this article, I will focus on the same objective. But this time, we will use only one aspect, which will be a mix of the two aspects of the last article.
If you remember, we used to create a main aspect, implementing IAspectProvider, which was returning an enumeration of aspects to be applied on each properties of the configuration sections.
This new aspect will keep the same structure. But instead of yielding an instance of CustomAttributeIntroductionAspect and an instance of ConfigurationPropertyInterceptor for each property, we will only return an instance of the former, and make the property interception part of the aspect.
To achieve this, we will use the advices and pointcuts, as stated here. To intercept the calls to the property getters, we will need the OnLocationGetValueAdvice attribute, in conjunction with the MulticastPointCut class with the correct values.
To intercept the calls to the properties setter, we need to use the OnLocationSetValueAdvice , with the same pointcuts.
We will also keep the same code as before in the body of these methods. Of course, we will have again to import the indexer in the aspect, which will oblige us to make the aspect implement the IInstanceScoped interface:
[Serializable]
[MulticastAttributeUsage(MulticastTargets.Class, Inheritance = MulticastInheritance.Strict)]
public class ConfigurationSectionAspect : TypeLevelAspect, IAspectProvider, IInstanceScopedAspect
{
//Same as before
#region Implementation of IAspectProvider
public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
{
Type targetType = (Type) targetElement;
var attributeType = typeof (ConfigurationPropertyAttribute);
var constructorInfo = attributeType.GetConstructor(new Type[] { typeof(string) });
foreach (PropertyInfo property in targetType.GetProperties(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance))
{
if (property.IsDefined(typeof(ConfigurationPropertyAttribute), false))
continue;
ObjectConstruction objectConstruction = new ObjectConstruction(constructorInfo, property.Name);
objectConstruction.NamedArguments.Add("IsRequired", ArePropertiesRequired);
CustomAttributeIntroductionAspect attributeIntroductionAspect = new CustomAttributeIntroductionAspect(objectConstruction);
// Yield only the attribute injection
yield return new AspectInstance(property, attributeIntroductionAspect);
}
}
#endregion
#region Implementation of IInstanceScopedAspect
public object CreateInstance(AdviceArgs adviceArgs)
{
return this.MemberwiseClone();
}
public void RuntimeInitializeInstance()
{
}
#endregion
[ImportMember("Item", IsRequired = true)]
public Property<object, string> IndexerMethod;
[OnLocationSetValueAdvice, MulticastPointcut(Targets = MulticastTargets.Property, Attributes = MulticastAttributes.Public | MulticastAttributes.NonAbstract)]
public void OnPropertySet(LocationInterceptionArgs args)
{
IndexerMethod.Set(args.LocationName, args.Value);
}
[OnLocationGetValueAdvice, MulticastPointcut(Targets = MulticastTargets.Property, Attributes = MulticastAttributes.Public | MulticastAttributes.NonAbstract)]
public void OnPropertyGet(LocationInterceptionArgs args)
{
object value = IndexerMethod.Get(args.LocationName);
args.Value = value;
}
}
If you compile this code and look at the output in Reflector, you will find a little problem. You will have a surprisingly high number of private sealed classes generated by PostSharp in your class. (Twice the normal count, to be exact).
This is because we didn't warn PostSharp that the interceptions shall be grouped together. What we need to do here is to make one of the advices be the master of the other advice, so the weaver know that they operate on the same level, as answered Gael to me on PostSharp's forum.
This leads us to this final aspect modification:
[OnLocationSetValueAdvice(Master = "OnPropertyGet")]
public void OnPropertySet(LocationInterceptionArgs args)
{
}
[OnLocationGetValueAdvice, MulticastPointcut(Targets = MulticastTargets.Property, Attributes = MulticastAttributes.Public | MulticastAttributes.NonAbstract)]
public void OnPropertyGet(LocationInterceptionArgs args)
{
}
Happy coding!