Consider the following code:
[AttributeUsage(validOn: AttributeTargets.Property)]
public sealed class ExcludeAttribute : Attribute
{
}
[PSerializable]
public sealed class PsDependencyPropertyAttribute : TypeLevelAspect, IAspectProvider
{
public PsDependencyPropertyAttribute()
{
}
public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
{
var targetType = (Type)targetElement;
//---
var introduceObfuscationAspect =
new CustomAttributeIntroductionAspect(
new ObjectConstruction(constructor: typeof(ObfuscationAttribute).GetConstructor(types: Type.EmptyTypes)));
introduceObfuscationAspect.CustomAttribute.NamedArguments.Add(key: "Feature", value: "renaming");
introduceObfuscationAspect.CustomAttribute.NamedArguments.Add(key: "Exclude", value: true);
introduceObfuscationAspect.CustomAttribute.NamedArguments.Add(key: "StripAfterObfuscation", value: true);
// add a Obfuscation attribute to every relevant property
foreach (var property
in targetType.GetProperties(
bindingAttr: BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly | BindingFlags.Instance)
.Where(
predicate: property =>
property.CanWrite &&
!property.IsDefined(attributeType: typeof(ExcludeAttribute), inherit: false)))
yield return new AspectInstance(targetElement: property, aspect: introduceObfuscationAspect);
//---
//! NATIVE PostSharp ATTRIBUTES DON'T GET PROCESSED IF THEY'RE INJECTED AT COMPILE TIME
var introduceDependencyPropertyAspect =
new CustomAttributeIntroductionAspect(
new ObjectConstruction(constructor: typeof(DependencyPropertyAttribute).GetConstructor(types: Type.EmptyTypes)));
// add a DependencyPropertyA attribute to every relevant property
foreach (var property
in targetType.GetProperties(
bindingAttr: BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance)
.Where(
predicate: property =>
property.CanWrite &&
!property.IsDefined(attributeType: typeof(ExcludeAttribute), inherit: false)))
yield return new AspectInstance(targetElement: property, aspect: introduceDependencyPropertyAspect);
}
}
Using this custom attribute does indeed inject the 2 attributes [DependencyProperty, Obfuscation(Feature = "renaming", Exclude = true, StripAfterObfuscation = true)]
, the only problem is that DependencyProperty
is a PostSharp attribute and doesn't get processed, just injected. And that's reasonable because the custom attribute tells PS just to inject those 2 attributes, BUT is there a way to have the PS DependencyProperty
processed when it's injected using a custom attribute?
You can provide DependencyPropertyAttribute
directly as an aspect to the target property instead of going via CustomAttributeIntroductionAspect
. For example:
yield return new AspectInstance(targetElement: property, aspect: new DependencyPropertyAttribute());
This is why DependencyPropertyAttribute
is not processed when introduced as an attribute:
PostSharp pipeline processes the assembly in several phases. The processing of the attributes is executed first, after that the aspect weavers are executed. If any aspect is emitting a new custom attribute during this phase, the attribute will not be processed by PostSharp anymore because the attribute processing phase has already completed.