Metadata Using - Attributes

 

範例如下

using System;

namespace ConsoleApp1
{
    [System.AttributeUsage(System.AttributeTargets.Class |
                       System.AttributeTargets.Struct,
                       AllowMultiple = true,
                       Inherited = true)]
    public class AuthorAttribute : System.Attribute
    {
        string name;
        public double version;

        public AuthorAttribute(string name)
        {
            this.name = name;

            // Default value.  
            version = 1.0;
        }

        public string GetName()
        {
            return name;
        }
    }

    // Class with the Author attribute. 
    [Author("P. Ackerman")]
    public class FirstClass
    {
        // ...  
    }

    // Class without the Author attribute.  
    public class SecondClass
    {
        // ...  
    }

    // Class with multiple Author attributes.  
    [Author("R. Koch", version = 2.0), Author("P. Ackerman")]
    public class ThirdClass
    {
        // ...  
    }

    class TestAuthorAttribute
    {
        public static void Test()
        {
            PrintAuthorInfo(typeof(FirstClass));
            PrintAuthorInfo(typeof(SecondClass));
            PrintAuthorInfo(typeof(ThirdClass));
        }

        private static void PrintAuthorInfo(System.Type t)
        {
            System.Console.WriteLine("Author information for {0}", t);

            // Using reflection.  
            System.Attribute[] attrs = System.Attribute.GetCustomAttributes(t);  // Reflection.  

            // Displaying output.  
            foreach (System.Attribute attr in attrs)
            {
                if (attr is AuthorAttribute)
                {
                    AuthorAttribute a = (AuthorAttribute)attr;
                    System.Console.WriteLine("   {0}, version {1:f}", a.GetName(), a.version);
                }
            }
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            TestAuthorAttribute TestAuthorAttribute = new TestAuthorAttribute();
            TestAuthorAttribute.Test();
            Console.ReadKey();
        }
    }

    /* Output:  
        Author information for FirstClass  
           P. Ackerman, version 1.00  
        Author information for SecondClass  
        Author information for ThirdClass  
           R. Koch, version 2.00  
           P. Ackerman, version 1.00  
    */
}

注意要點分成三個部份,自訂 Attribute、套用 Attribute、處理 Attribute。

一、自訂 Attribute

1、自訂 Attribute 時,類別必須繼承 System.Attribute。

2、可以利用 System.AttributeUsage 來設定 ValidOn、AllowMultiple、Inherited 三個參數。

3、ValidOn 參數的套用,可以對自訂 Attribute 作出應用限制,ValidOn 參數是指 AttributeTargets Enum

預設值是 AttributeTargets.All。

4、AllowMultiple 預設值為 false,Inherited 預設值為 true。

5、另一種對自訂 Attribute 作出應用限制,是指 Attribute targets

[type: System.AttributeUsage(System.AttributeTargets.Class |
                   System.AttributeTargets.Struct,
                   AllowMultiple = true,
                   Inherited = true)]
public class AuthorAttribute : System.Attribute
{
    string name;
    public double version;

    public AuthorAttribute(string name)
    {
        this.name = name;

        // Default value.  
        version = 1.0;
    }

    public string GetName()
    {
        return name;
    }
}

 

Target value Applies to
assembly Entire assembly
module Current assembly module
field Field in a class or a struct
event Event
method Method or 「get」 and 「set」 property accessors
param Method parameters or 「set」 property accessor parameters
property Property
return Return value of a method, property indexer, or 「get」 property accessor
type Struct, class, interface, enum, or delegate

而有定義 Attribute targets 時,AttributeUsage 的 ValidOn 參數的設定可能會被忽略?

 

二、套用 Attribute

1、自訂 Attribute 名稱時,名稱的命名慣例可以帶有 Attribute 字尾;

而在套用 Attribute 名稱時,也可以省略 Attribute 字尾。

2、自訂 Attribute 的 class 一定要為 public,才能被他人使用。

3、Attribute 除了可以套在 class 上之外,也可以套在方法上;

而在 C# 7.3 更加可以套在 property、field 上。

using System;
using System.Reflection;

// An enumeration of animals. Start at 1 (0 = uninitialized).
public enum Animal
{
    // Pets.
    Dog = 1,
    Cat,
    Bird,
}

// A custom attribute to allow a target to have a pet.
public class AnimalTypeAttribute : Attribute
{
    // The constructor is called when the attribute is set.
    public AnimalTypeAttribute(Animal pet)
    {
        thePet = pet;
    }

    // Keep a variable internally ...
    protected Animal thePet;

    // .. and show a copy to the outside world.
    public Animal Pet
    {
        get { return thePet; }
        set { thePet = value; }
    }
}

// A test class where each method has its own pet.
class AnimalTypeTestClass
{
    [AnimalType(Animal.Dog)]
    public void DogMethod() { }

    [AnimalType(Animal.Cat)]
    public void CatMethod() { }

    [AnimalType(Animal.Bird)]
    public void BirdMethod() { }
}

class DemoClass
{
    static void Main(string[] args)
    {
        AnimalTypeTestClass testClass = new AnimalTypeTestClass();
        Type type = testClass.GetType();
        // Iterate through all the methods of the class.
        foreach (MethodInfo mInfo in type.GetMethods())
        {
            // Iterate through all the Attributes for each method.
            foreach (Attribute attr in
                Attribute.GetCustomAttributes(mInfo))
            {
                // Check for the AnimalType attribute.
                if (attr.GetType() == typeof(AnimalTypeAttribute))
                    Console.WriteLine(
                        "Method {0} has a pet {1} attribute.",
                        mInfo.Name, ((AnimalTypeAttribute)attr).Pet);
            }

        }

        Console.ReadKey();
    }
}
/*
 * Output:
 * Method DogMethod has a pet Dog attribute.
 * Method CatMethod has a pet Cat attribute.
 * Method BirdMethod has a pet Bird attribute.
 */

 

三、處理 Attribute

主要的關鍵在於 Attribute.GetCustomAttribute

Attribute.GetCustomAttributesType.GetMethods

Type.GetPropertiesType.GetConstructors 方法的使用。

 

參考資料:

AttributeUsageAttribute Class

AttributeTargets Enum

Attribute Class

Attributes (C#)

Extending Metadata Using Attributes