Home Random Page


CATEGORIES:

BiologyChemistryConstructionCultureEcologyEconomyElectronicsFinanceGeographyHistoryInformaticsLawMathematicsMechanicsMedicineOtherPedagogyPhilosophyPhysicsPolicyPsychologySociologySportTourism






Nbsp;   Defining Your Own Attribute Class

You know that an attribute is an instance of a class derived from System.Attribute, and you also know how to apply an attribute. Let’s now look at how to define your own custom attribute classes. Say you’re the Microsoft employee responsible for adding the bit flag support to enumerated types. To accomplish this, the first thing you have to do is define a FlagsAttribute class.

 

namespace System {

public class FlagsAttribute : System.Attribute { public FlagsAttribute() {

}

}

}

 

Notice that the FlagsAttribute class inherits from Attribute; this is what makes the Flags­ Attribute class a CLS-compliant custom attribute. In addition, the class’s name has a suffix of Attribute; this follows the standard convention but is not mandatory. Finally, all non-abstract attributes must contain at least one public constructor. The simple FlagsAttribute constructor takes no parameters and does absolutely nothing.

       
   
 
 

 

So far, instances of the FlagsAttribute class can be applied to any target, but this attribute should really be applied to enumerated types only. It doesn’t make sense to apply the attribute to a property or a method. To tell the compiler where this attribute can legally be applied, you apply


an instance of the System.AttributeUsageAttribute class to the attribute class. Here’s the new code.

 

namespace System {

[AttributeUsage(AttributeTargets.Enum, Inherited = false)] public class FlagsAttribute : System.Attribute {

public FlagsAttribute() {

}

}

}

 

In this new version, I’ve applied an instance of AttributeUsageAttribute to the attribute. After all, the attribute type is just a class, and a class can have attributes applied to it. The Attribute­ Usage attribute is a simple class that allows you to specify to a compiler where your custom attribute can legally be applied. All compilers have built-in support for this attribute and generate errors when a user-defined custom attribute is applied to an invalid target. In this example, the AttributeUsage attribute specifies that instances of the Flags attribute can be applied only to enumerated type targets.

Because all attributes are just types, you can easily understand the AttributeUsageAttribute

class. Here’s what the FCL source code for the class looks like.

 

[Serializable]

[AttributeUsage(AttributeTargets.Class, Inherited=true)] public sealed class AttributeUsageAttribute : Attribute {

internal static AttributeUsageAttribute Default =

new AttributeUsageAttribute(AttributeTargets.All);

 

internal Boolean m_allowMultiple = false;

internal AttributeTargets m_attributeTarget = AttributeTargets.All; internal Boolean m_inherited = true;

 

// This is the one public constructor

public AttributeUsageAttribute(AttributeTargets validOn) { m_attributeTarget = validOn;

}

 

internal AttributeUsageAttribute(AttributeTargets validOn, Boolean allowMultiple, Boolean inherited) { m_attributeTarget = validOn;



m_allowMultiple = allowMultiple; m_inherited = inherited;

}

 

public Boolean AllowMultiple {

get { return m_allowMultiple; } set { m_allowMultiple = value; }

}

 

public Boolean Inherited {

get { return m_inherited; } set { m_inherited = value; }

}


public AttributeTargets ValidOn { get { return m_attributeTarget; }

}

}

 

As you can see, the AttributeUsageAttribute class has a public constructor that allows you to pass bit flags that indicate where your attribute can legally be applied. The System.Attribute­ Targets enumerated type is defined in the FCL as follows.

 

[Flags, Serializable]

public enum AttributeTargets { Assembly = 0x0001,

Module = 0x0002,

Class = 0x0004,

Struct = 0x0008,

Enum = 0x0010,

Constructor = 0x0020,

Method = 0x0040,

Property = 0x0080,

Field = 0x0100,

Event = 0x0200,

Interface = 0x0400,

Parameter = 0x0800,

Delegate = 0x1000,

ReturnValue = 0x2000, GenericParameter = 0x4000,

All = Assembly | Module | Class | Struct | Enum | Constructor | Method | Property | Field | Event | Interface | Parameter | Delegate | ReturnValue | GenericParameter

}

 

The AttributeUsageAttribute class offers two additional public properties that can optionally be set when the attribute is applied to an attribute class: AllowMultiple and Inherited.

For most attributes, it makes no sense to apply them to a single target more than once. For ex- ample, nothing is gained by applying the Flags or Serializable attributes more than once to a single target. In fact, if you tried to compile the following code, the compiler would report the follow- ing message: error CS0579: Duplicate 'Flags' attribute.

 

[Flags][Flags] internal enum Color {

Red

}

 

For a few attributes, however, it does make sense to apply the attribute multiple times to a single target. In the FCL, the ConditionalAttribute attribute class allows multiple instances of itself to be applied to a single target. If you don’t explicitly set AllowMultiple to true, your attribute can be applied no more than once to a selected target.


AttributeUsageAttribute’s other property, Inherited, indicates if the attribute should be ap- plied to derived classes and overriding methods when applied on the base class. The following code demonstrates what it means for an attribute to be inherited.

 

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited=true)] internal class TastyAttribute : Attribute {

}

 

[Tasty][Serializable] internal class BaseType {

 

[Tasty] protected virtual void DoSomething() { }

}

 

internal class DerivedType : BaseType { protected override void DoSomething() { }

}

 

In this code, DerivedType and its DoSomething method are both considered Tasty because the TastyAttribute class is marked as inherited. However, DerivedType is not serializable because the FCL’s SerializableAttribute class is marked as a noninherited attribute.

Be aware that the .NET Framework considers targets only of classes, methods, properties, events, fields, method return values, and parameters to be inheritable. So when you’re defining an attribute type, you should set Inherited to true only if your targets include any of these targets. Note that inherited attributes do not cause additional metadata to be emitted for the derived types into the managed module. I’ll say more about this a little later in the “Detecting the Use of a Custom Attri- bute” section.

       
   
 
 

 

 


Date: 2016-03-03; view: 692


<== previous page | next page ==>
Nbsp;   Using Custom Attributes | Nbsp;   Attribute Constructor and Field/Property Data Types
doclecture.net - lectures - 2014-2024 year. Copyright infringement or personal data (0.009 sec.)