屬性
屬性提供將元數據或宣告式資訊與程式代碼產生關聯的強大方式(元件、類型、方法、屬性等等)。 將屬性與程式實體產生關聯之後,您可以使用稱為「反映」的技術,在運行時間查詢屬性。
屬性具有下列屬性:
- 屬性會將元數據新增至您的程式。 元數據 是程式中所定義類型的相關信息。 所有 .NET 元件都包含一組指定的元數據,描述元件中定義的類型和類型成員。 您可以新增自訂屬性來指定任何其他必要資訊。
- 屬性可以套用至整個元件、模組或較小的程序專案,例如類別和屬性。
- 屬性可以接受與方法和屬性相同的引數。
- 屬性可讓程式使用反射,檢查其自身的元數據或其他程式中的元數據。
與反思一起工作
反射 提供的 API Type 描述元件、模組和類型。 您可以使用反映來動態建立類型的實例、將類型系結至現有的物件,或從現有的物件取得類型,以及叫用其方法或存取其字段和屬性。 當您在程式代碼中使用屬性時,反映可讓您存取它們。 如需詳細資訊,請參閱 屬性。
以下是使用 GetType() 方法的簡單反映範例。
Object
基類中的所有類型都會繼承這個方法,用來取得變數的類型:
注意
請務必在 C# (.cs) 程式代碼檔案頂端新增 using System;
和 using System.Reflection;
語句。
// Using GetType to obtain type information:
int i = 42;
Type type = i.GetType();
Console.WriteLine(type);
輸出會顯示類型:
System.Int32
下列範例會使用反映來取得載入元件的完整名稱。
// Using Reflection to get information of an Assembly:
Assembly info = typeof(int).Assembly;
Console.WriteLine(info);
輸出類似於下列範例:
System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e
IL 的關鍵詞差異
C# 關鍵詞 protected
和 internal
在中繼語言中沒有意義,而且不會在反映 API 中使用。 IL 中的對應詞彙是 Family 和 Assembly。 以下是一些您可以使用這些詞彙的方式:
- 若要使用反映來識別
internal
方法,請使用 IsAssembly 屬性。 - 若要識別
protected internal
方法,請使用 IsFamilyOrAssembly。
使用屬性
屬性幾乎可以放在任何宣告上,不過特定屬性可能會限制其有效宣告的類型。 在 C# 中,您會在套用實體的宣告上方放置以方括弧 ([]
) 括住的屬性名稱,以指定屬性。
在此範例中,您會使用 SerializableAttribute 屬性將特定特性套用至類別:
[Serializable]
public class SampleClass
{
// Objects of this type can be serialized.
}
您可以使用 DllImportAttribute 屬性來宣告方法:
[System.Runtime.InteropServices.DllImport("user32.dll")]
extern static void SampleMethod();
您可以在宣告上放置多個屬性:
void MethodA([In][Out] ref double x) { }
void MethodB([Out][In] ref double x) { }
void MethodC([In, Out] ref double x) { }
某些屬性可以針對指定的實體指定多次。 下列範例顯示 ConditionalAttribute 屬性的多重使用:
[Conditional("DEBUG"), Conditional("TEST1")]
void TraceMethod()
{
// ...
}
注意
依照慣例,所有屬性名稱都會以後綴 「Attribute」 結尾,以區別它們與 .NET 連結庫中的其他類型。 不過,當您在程式代碼中使用屬性時,不需要指定屬性後綴。 例如,[DllImport]
宣告相當於 [DllImportAttribute]
宣告,但 DllImportAttribute
是 .NET 類別庫中類別的實際名稱。
屬性參數
許多屬性都有參數,這些參數可以 位置、未命名,或名為 的。 下表說明如何操作具名屬性與位置屬性:
位置參數
屬性建構函式的參數:
具名參數
屬性的屬性或欄位:
- 必須指定,不能省略
- 永遠先指定
- 以 特定 順序指定
- 一律為選擇性,若為 false,請省略
- 指定位置參數之後
- 依任何順序指定
例如,下列程式代碼顯示三個對等 DllImport
屬性:
[DllImport("user32.dll")]
[DllImport("user32.dll", SetLastError=false, ExactSpelling=false)]
[DllImport("user32.dll", ExactSpelling=false, SetLastError=false)]
第一個參數是 DLL 名稱,該名稱具有位置性,且一律放在最前面。 其他實例被稱為參數名稱。 在此案例中,這兩個具名參數預設為 false,因此可以省略它們。 如需預設參數值的相關信息,請參閱個別屬性的檔。 如需允許參數類型的詳細資訊,請參閱 C# 語言規格的 屬性 一節。
屬性目標
屬性的 目標 是屬性所套用的實體。 例如,屬性可以套用至類別、方法或元件。 預設情況下,屬性會套用至其後方的元素。 但您也可以明確識別要關聯的元素,例如方法、參數或傳回值。
若要明確識別屬性目標,請使用下列語法:
[target : attribute-list]
下表顯示可能 target
值的清單。
目標值 | 適用於 |
---|---|
assembly |
整個組裝 |
module |
目前的組件模組 |
field |
類別或結構中的欄位 |
event |
事件 |
method |
方法或 get 和 set 屬性存取子 |
param |
方法參數或 set 屬性存取器參數 |
property |
財產 |
return |
傳回值來自方法、屬性索引器或 get 屬性存取子 |
type |
結構、類別、介面、列舉或委派 |
您可以指定 field
目標值,將屬性套用至針對自動實作屬性 所建立的備份欄位。
下列範例示範如何將屬性套用至元件和模組。 如需詳細資訊,請參閱 通用屬性 (C#)。
using System;
using System.Reflection;
[assembly: AssemblyTitleAttribute("Production assembly 4")]
[module: CLSCompliant(true)]
下列範例示範如何將屬性套用至 C# 中的方法、方法參數和方法傳回值。
// default: applies to method
[ValidatedContract]
int Method1() { return 0; }
// applies to method
[method: ValidatedContract]
int Method2() { return 0; }
// applies to parameter
int Method3([ValidatedContract] string contract) { return 0; }
// applies to return value
[return: ValidatedContract]
int Method4() { return 0; }
注意
不論定義 ValidatedContract
屬性的目標是否有效,return
目標都必須指定,即使已定義 ValidatedContract
屬性以只套用至傳回值也一樣。 換句話說,編譯程式不會使用 AttributeUsage
信息來解析模棱兩可的屬性目標。 如需詳細資訊,請參閱 AttributeUsage。
檢視使用屬性的方式
以下是在程式代碼中使用屬性的一些常見方式:
- 使用
HttpPost
屬性標記回應 POST 訊息的控制器方法。 如需詳細資訊,請參閱 HttpPostAttribute 類別。 - 描述如何在與本機程式碼互通時封送方法參數。 如需詳細資訊,請參閱 MarshalAsAttribute 類別。
- 描述類別、方法和介面的元件物件模型 (COM) 屬性。
- 使用 DllImportAttribute 類別呼叫非受管程式碼。
- 在標題、版本、描述或商標方面描述您的組件。
- 描述要序列化以進行持續化的類別成員。
- 描述如何在 XML 序列化中對應類別成員與 XML 節點。
- 描述方法的安全性需求。
- 指定用來強制執行安全性的特性。
- 使用即時編譯器(JIT)控制優化,讓程式碼保持容易除錯。
- 取得方法呼叫端的相關信息。
檢閱反思情境
反思在下列情況中很有用:
- 存取程式元數據中的屬性。 如需詳細資訊,請參閱 擷取儲存在屬性中的資訊。
- 檢查並具現化元件中的類型。
- 使用 System.Reflection.Emit 命名空間中的類別在運行時間建置新的類型。
- 在執行期間建立的類型上執行延遲綁定和存取方法。 如需詳細資訊,請參閱 動態載入和使用類型。