自訂特性允許任何人擴充中繼資料格式,如果在現有中繼資料格式中,一個欄位或者方法的某個方面無法擷取,那麼就可以用自訂特性來表示那個方面。可以通過反射或者中繼資料介面來讀取自訂特性。自訂特性作為BLOB(二進位大對象塊)儲存在CLR中繼資料中。自訂特性的存在與否不影響CLR對類型的處理。相反,自訂特性處於一種休眠狀態,等待程式用反射或者中繼資料介面讀取它們。
用枚舉控制檔案的讀寫很方便,但是需要在枚舉前面加上FlagsAttribute進行修飾。下面可以看個執行個體,說明下有無FlagsAttribute修飾對結果的影響。
[Flags]
public enum Fruit
{
peach = 0x01,
banana = 0x02,
orange = 0x04,
apple = 0x10
}
static void Main(string[] args)
{
Fruit f=Fruit.peach|Fruit.banana;
Console.WriteLine("It has FlagsAttribute: " + f.ToString());
//Console.WriteLine("It has not FlagsAttribute: " + f.ToString());
Console.ReadLine();
}
有無Flags的運行結果:
查看Enum類的原始碼的ToString()方法如下,IsDefined方法判斷是否存在FlagsAttribute特性而執行不同的分支。
下面模仿Enum類的tostring()方法,我也寫了個demo,可以更深刻的感悟自訂特性,一定要記住自訂特性不改變CLR對類型的處理方式,只是我們通過反射或中繼資料介面讀取自訂特性執行個體資料來人為的控製程序執行執行分支。
public class FruitCustomAttribute : System.Attribute
{
public string Name = string.Empty;
public string FruitName = string.Empty;
public FruitCustomAttribute(string name)
{
Name = name;
}
}
[FruitCustom("Feng", FruitName = "Peach")]
public class Fruit
{
public override string ToString()
{
if (this.GetType().IsDefined(typeof(FruitCustomAttribute), false))
{
Attribute attr = Attribute.GetCustomAttribute(this.GetType(), typeof(FruitCustomAttribute), false);
if (attr != null)
{
return string.Format("{0} likes to eat {1}.", ((FruitCustomAttribute)attr).Name,
((FruitCustomAttribute)attr).FruitName);
}
}
return base.ToString();
}
}
class Program
{
static void Main(string[] args)
{
Fruit f = new Fruit();
Console.WriteLine(f.ToString());
Console.ReadLine();
}
}
執行結果: