An aspect can add or remove custom attributes to or from any declaration. There are several ways to accomplish this, depending on whether the declaration exists in the code model or is being added by the aspect.
Adding attributes to an existing declaration
To add a custom attribute to a declaration that exists before the aspect is applied, use the IntroduceAttribute method. This method requires an argument of type IAttributeData. This interface is implemented by the IAttribute interface, allowing you to introduce any custom attribute that you find in the code model via the IDeclaration.Attributes property. To create a new custom attribute, use the AttributeConstruction.Create method. This method requires the attribute type or constructor along with two optional sets of arguments: constructor arguments are the arguments of the constructor, and named arguments are the values assigned to fields and properties.
Example: adding EditorBrowsableAttribute to fields
The following aspect adds EditorBrowsableAttribute to all fields whose name starts with a double underscore.
1using Metalama.Framework.Advising;
2using Metalama.Framework.Aspects;
3using Metalama.Framework.Code;
4using Metalama.Framework.Code.DeclarationBuilders;
5using System.ComponentModel;
6using System.Linq;
7
8#pragma warning disable CA1310 // Specify StringComparison for correctness
9
10namespace Doc.AddEditorBrowsableAttribute;
11
12public class HideFieldsFromEditorAttribute : TypeAspect
13{
14 public override void BuildAspect( IAspectBuilder<INamedType> builder )
15 {
16 // Construct a custom attribute.
17 var attribute = AttributeConstruction.Create(
18 typeof(EditorBrowsableAttribute),
19 new object[] { EditorBrowsableState.Never } );
20
21 // Add a copy of it to each field whose name starts with a double underscore.
22 foreach ( var field in builder.Target.Fields
23 .Where( f => f.Name.StartsWith( "__" ) && !f.IsImplicitlyDeclared ) )
24 {
25 builder.With( field ).IntroduceAttribute( attribute );
26 }
27 }
28}
1namespace Doc.AddEditorBrowsableAttribute;
2
3[HideFieldsFromEditor]
4public class C
5{
6 public int NormalField;
7#pragma warning disable IDE1006 // Naming Styles
8 public string? __HiddenField;
9#pragma warning restore IDE1006 // Naming Styles
10}
1using System.ComponentModel;
2
3namespace Doc.AddEditorBrowsableAttribute;
4
5[HideFieldsFromEditor]
6public class C
7{
8 public int NormalField;
9#pragma warning disable IDE1006 // Naming Styles
10 [EditorBrowsable(EditorBrowsableState.Never)]
11 public string? __HiddenField;
12#pragma warning restore IDE1006 // Naming Styles
13}
Removing attributes from an existing declaration
To remove all custom attributes of a given type from a declaration, use the RemoveAttributes method.
Note that you cannot edit a custom attribute; instead, you must remove previous instances and add new ones.
Adding attributes to an introduced declaration, declaratively
When your aspect introduces a new declaration in a declarative way, i.e., using the [Introduce] custom attribute, you can add any custom attribute to the new member by adding the attribute to the template.
Example: declaratively introducing a field with EditorBrowsableAttribute
The next example demonstrates an aspect that introduces a field hidden from the editor by EditorBrowsableAttribute. The custom attribute is copied from the template to the target declaration.
1using Metalama.Framework.Aspects;
2using System.ComponentModel;
3
4namespace Doc.AddEditorBrowsableAttribute_Introduced_Declarative;
5
6public class AddEditorHiddenFieldAttribute : TypeAspect
7{
8 [Introduce]
9 [EditorBrowsable( EditorBrowsableState.Never )]
10#pragma warning disable IDE1006 // Naming Styles
11 public string? __HiddenField;
12#pragma warning restore IDE1006 // Naming Styles
13}
1namespace Doc.AddEditorBrowsableAttribute_Introduced_Declarative;
2
3[AddEditorHiddenFieldAttribute]
4public class C
5{
6 public int NormalField;
7}
1using System.ComponentModel;
2
3namespace Doc.AddEditorBrowsableAttribute_Introduced_Declarative;
4
5[AddEditorHiddenFieldAttribute]
6public class C
7{
8 public int NormalField;
9 [EditorBrowsable(EditorBrowsableState.Never)]
10 public string? __HiddenField;
11}
Adding attributes to an introduced declaration, programmatically
The second, more advanced method to introduce declarations into a type is to call one of the Introduce*
methods of the AdviserExtensions class. This technique is described in Introducing members. These methods accept an optional delegate that can configure the declaration being introduced. This delegate receives an IDeclarationBuilder, and you can use the AddAttribute and RemoveAttributes methods as described above.
Example: programmatically introducing a field with EditorBrowsableAttribute
1using Metalama.Framework.Advising;
2using Metalama.Framework.Aspects;
3using Metalama.Framework.Code;
4using Metalama.Framework.Code.DeclarationBuilders;
5using System.ComponentModel;
6
7namespace Doc.AddEditorBrowsableAttribute_Introduced_Programmatic;
8
9public class AddEditorHiddenFieldAttribute : TypeAspect
10{
11 public override void BuildAspect( IAspectBuilder<INamedType> builder )
12 {
13 var attribute = AttributeConstruction.Create(
14 typeof(EditorBrowsableAttribute),
15 new object[] { EditorBrowsableState.Never } );
16
17 builder.IntroduceField(
18 "__HiddenField",
19 typeof(int),
20 buildField: f => f.AddAttribute( attribute ) );
21 }
22}
1namespace Doc.AddEditorBrowsableAttribute_Introduced_Programmatic;
2
3[AddEditorHiddenFieldAttribute]
4public class C
5{
6 public int NormalField;
7}
1using System.ComponentModel;
2
3namespace Doc.AddEditorBrowsableAttribute_Introduced_Programmatic;
4
5[AddEditorHiddenFieldAttribute]
6public class C
7{
8 public int NormalField;
9 [EditorBrowsable(EditorBrowsableState.Never)]
10 private int __HiddenField;
11}