元數據 (CLI)

通用語言架構（CLI）中的元數據是指嵌入通用中間語言（CIL）代碼中的某些數據結構，用於描述代碼的高級結構。元數據描述程序集中定義的所有類和類成員，以及當前程序集將從另一個程序集中調用的類和類成員。方法的元數據包含該方法的完整描述，包括類（以及包含該類的程序集）、return type和所有方法參數。

CLI語言列表編譯器將生成元數據並將其存儲在包含CIL的程序集中。當運行時執行CIL時，它將檢查以確保被調用方法的元數據與存儲在調用方法中的元數據相同。這確保了只能使用正確數量的參數和正確的參數類型來調用方法。

Windows Runtime應用程式平台存在於Windows 8和Windows Phone 8中，它使用CLI元數據格式來描述以任何支持的程式語言編寫的代碼的組件接口。與通用語言運行庫中使用的不同之處在於，程序集通常不包含任何CIL指令。

## 特性

開發人員可以通過「特性」（attribute）將元數據添加到代碼中。有兩種類型的特性，自定義特性和偽自定義特性，對開發人員來說，它們具有相同的句法。代碼中的特性是給編譯器生成元數據的消息。在CIL中，諸如繼承修飾符、作用域修飾符之類的元數據，以及幾乎所有不是操作碼或流的東西，也被稱為特性。

自定義特性是一個常規的類，它繼承自`attribute`類。自定義特性可以用於任何方法、屬性、類或整個程序集，語法為：`[“AttributeName”（可选“parameter”对，可选“name=value”对）]`，如下所示：

```csharp
[Custom]
[Custom(1)]
[Custom(1, Comment="yes")]
```

CLI廣泛使用自定義特性。Windows Communication Framework使用特性來定義服務契約，ASP.NET使用這些特性將方法公開為Web服務，LINQ to SQL使用它們來定義類到基礎關係架構的映射，Microsoft Visual Studio使用它們將對象的屬性分組在一起，類開發人員通過應用`[category]`自定義特性來指示對象類的類別。自定義特性由應用程式代碼而不是CLR來解釋。當編譯器看到自定義特性時，它將生成CLR無法識別的自定義元數據。開發人員必須提供代碼來讀取元數據並對其進行操作。例如，示例中顯示的特性可以由代碼處理：

```csharp
class CustomAttribute : Attribute
{
   private int paramNumber = 0;
   private string comment = "";

   public CustomAttribute() { }
   public CustomAttribute(int num) { paramNumber = num; }

   public String Comment
   {
      set { comment = value; }
   }
}
```

類的名稱將映射到特性名稱。Visual C#編譯器會自動在任何特性名稱的末尾添加字串「`Attribute`」。因此，每個特性類名都應該以這個字串結尾，但定義一個沒有`attribute`-後綴的屬性是合法的。將特性附加到項時，編譯器將同時查找文字名稱和末尾添加了`attribute`的名稱；即如果要編寫`[Custom]`，編譯器將同時查找`Custom`和`CustomAttribute`。如果兩者都存在，編譯器將失敗。如果您不想冒歧義的風險，該特性可以以「`@`」為前綴，因此寫入`[@Custom]`將與`CustomAttribute`不匹配。使用特性調用類的構造函數。支持重載構造函數。名稱-值對映射到特性，名稱表示特性的名稱，提供的值由特性設置。

有時，程式設計師所附加的屬性會有歧義。請考慮以下代碼：

```csharp
[Orange]
public int ExampleMethod(string input)
{
    //method body goes here
}
```

What has been marked as orange? Is it the `ExampleMethod`, its return value, or perhaps the entire assembly? In this case, the compiler will default, and treat the attribute as being affixed to the method. If this is not what was intended, or if the author wishes to clarify their code, an attribute target may be specified. Writing `[return: Orange]` will mark the return value as orange, `[assembly: Orange]` will mark the entire assembly. The valid targets are `assembly`, `field`, `event`, `method`, `module`, `param`, `property`, `return` and `type`. 什麼被標記為橙色？是`ExampleMethod`、它的返回值，還是整個程序集？在這種情況下，編譯器將默認，並將特性視為附加到方法上。如果這不是預期的，或者如果作者希望澄清他們的代碼，可以指定「特性目標」。寫入`[return：Orange]`將返回值標記為橙色，`[assembly:Orange]`將標記整個程序集。有效的目標是`assembly`、`field`和`event`，`method`, `module`, `param`, `property`, `return` 和 `type`。

偽自定義特性與常規自定義特性一樣使用，但它們沒有自定義處理程序；相反，編譯器具有對特性的內在感知，並以不同的方式處理標記有這些特性的代碼。諸如`Serializable`和`Obsolete`之類的特性被實現為偽自定義特性。ILAsm不應該使用偽自定義特性，因為它有足夠的語法來描述元數據。

## 元數據存儲

程序集包含元數據表。這些表格由CIL規範描述。元數據表將具有零個或多個條目，並且條目的位置決定其索引。當CIL代碼使用元數據時，它通過元數據令牌（token）來使用元數據。這是一個32-比特值，其中前8位標識適當的元數據表，其餘24位給出表中元數據的索引。Framework SDK包含一個名為metainfo的示例，該示例將列出程序集中的元數據表，但是，這些資訊很少對開發人員有用。可以使用.NET Framework SDK提供的ILDASM工具查看程序集中的元數據。

在CIL標準中，元數據以ILAsm（彙編語言）形式、用於存儲的磁碟上表示形式以及嵌入可移植可執行文件（PE、.exe或.dll）格式的程序集中的形式進行定義。PE表格基於磁碟上的表格。

## 反射

反射是用於讀取CLI元數據的API。反射API提供元數據的邏輯視圖，而不是metainfo等工具提供的文本視圖。.NET框架1.1版中的反射可用於檢查類及其成員的描述，並調用方法。但是，它不允許在運行時訪問方法的CIL。該框架的2.0版允許獲得方法的CIL。

## 其他元數據工具

除了SystemReflection命名空間之外，還提供了其他可用於處理元數據的工具。Microsoft.NET Framework附帶了一個CLR元數據操作庫，該庫在原生代碼中實現。檢索和操作元數據的第三方工具包括和也可以使用。

## 基本資料

- 日語原文：CLI元數據, 磁碟上表示
- 標準：ECMA-335 part II
- magic：0x424A5342
- 開發者：Microsoft、Ecma International
- 擴展名：.exe, .dll, .winmd