@TOC這篇文章主要面向的對象是初級開發人員,以及對屬性不是很熟悉的開發人員。
什麼是屬性(Attribute)
屬性在C#中很常用,但有部分開發人員對它既熟悉又陌生。概念上屬性是将中繼資料關聯到元素的方式。屬性的使用方法我們在代碼中經常肩見到,比如下面這樣的:
[Test]
public class MyClass
{
//more code
}
在上面的樣例代碼中Test就是一個屬性。屬性是放在類、字段和方法等定義的前面(上面),用來指定特定内容的。.Net架構中為我們提供了一些常用屬性。比如Serializable,它告訴編譯器目前類可以序列化成JSON或XML。
TIP:屬性在編譯的時候會嵌入到程式集中。我們可以使用反射來獲得屬性的值。
自定義屬性
當.Net架構提供的屬性不足以滿足我們開發的要求時,我們可以自定義屬性,自定義屬性在項目中算比較常用的技術。定義自定義屬性需繼承抽象類System.Attribute。比如當建立一個汽車類,需要一個屬性來表示汽車的品牌、型号時,我們可以像下面代碼這樣實作自定義屬性:
public class CarAttribute : Attribute
{
public string Brand { get; set; }
public string Model { get; set; }
public CarAttribute (string brand, int model)
{
Brand = brand;
Model = model;
}
}
通過上面的代碼我們可以看出,屬性其實就是一個類,它和其它類一樣,也擁有字段、方法、構造函數等成員。
如何使用屬性
在本文的前面說過,屬性可以放在類、字段和方法等定義的前面(上面),那麼,我們來看一下如何使用上一小節中自定義的屬性,代碼如下:
[Car("BMW", "x3")]
public class Carriage
{
//more code
}
在這裡這兒需要注,自定義屬性的名字,如果我使用的是xxx+Attribute的形式來命名名稱的話,那麼在使用時可以用短名稱xxx(例如上面代碼中的Car就是使用的是CarAttribute的短名稱)
限制屬性使用範圍
屬性本身是一個類,是以屬性也可以用其他屬性來指定和修飾。常用的修飾屬性的屬性是AttributeUsage 屬性,它用來限制自定義屬性可以修飾的元素類型,例如我們将CarAttribute屬性的使用範圍限制為類和接口,可以這麼做:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)]
public class CarAttribute: Attribute
{
//more code
}
AttributeUsage屬性的參數AttributeTargets是一個枚舉,包括類、接口、方法、構造函數、枚舉、程式集等枚舉内容。經過修改後的CarAttribute屬性隻能用在類和接口中,如果用它來修飾字段,編譯器就會報錯。
AttributeUsage還允許我們定義從修飾對象繼承的對象,是否也獲得該屬性。同樣我們将CarAttribute修改為從修飾對象繼承的對象可以獲得該屬性:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, Inherited = true)]
public class CarAttribute: Attribute
{
//more code
}
同時我們也能指定屬性是否可以在一個元素上有多個執行個體,例如下面的代碼就定義了CarAttribute屬性不允許在一個元素上有多個執行個體:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = false)]
public class CarAttribute: Attribute
{
//more code
}
如何通路屬性
到這裡一定有小夥伴問,如何通路屬性呢?其實.NET架構為我們提供了Attribute.GetCustomAttribute()方法來通路屬性,簡單的用法如下:
var carType = typeof(Carriage);
var attributeType = typeof(CarAttribute);
var attribute = (CarAttribute)Attribute.GetCustomAttribute(carType , attributeType);
Console.WriteLine($"Car is {attribute.Brand} {attribute.Model}");
反射通路
除了上面的通路方式外,還有一種常用的通路方式:反射通路。反射的主要的作用是用來收集對象的資料而不是對象本身的資料。這些資料包括對象的類型、對象的成員的資訊、特定程式集資訊以及存儲在元素屬性中的任何資訊。最簡單的反射是GetType()方法,代碼如下:
int myNum= 88;
Type type = myNum.GetType();
Console.WriteLine(type);
Assembly mobileAssembly = typeof(Carriage).Assembly;
Console.WriteLine(mobileAssembly);
PropertyInfo property = reflected.GetType().GetProperty("PropertyOne");
Console.WriteLine(property);
ConstructorInfo constructor = reflected.GetType().GetConstructor(new Type[0]);
Console.WriteLine(constructor);