非受控類型條件約束Unmanaged type constraint


未受管理的條件約束功能將會在 c # 語言規格中,將語言強制授與稱為「非受控型別」的類型類別。 這是在第18.2 節中定義為類型,此類型不是參考型別,而且不包含任何嵌套層級的參考型別字段。The unmanaged constraint feature will give language enforcement to the class of types known as "unmanaged types" in the C# language spec. This is defined in section 18.2 as a type which is not a reference type and doesn't contain reference type fields at any level of nesting.


主要動機是讓您更輕鬆地以 c # 撰寫低層級 interop 程式碼。The primary motivation is to make it easier to author low level interop code in C#. 非受控型別是 interop 程式碼的其中一個核心構成要素,但不支援泛型,因此不可能在所有非受控類型上建立可重複使用的常式。Unmanaged types are one of the core building blocks for interop code, yet the lack of support in generics makes it impossible to create re-usable routines across all unmanaged types. 相反地,開發人員會被迫針對其媒體櫃中的每個非受控類型撰寫相同的定案板程式碼:Instead developers are forced to author the same boiler plate code for every unmanaged type in their library:

int Hash(Point point) { ... } 
int Hash(TimeSpan timeSpan) { ... } 

若要啟用這種類型的案例,語言將引進新的條件約束:非受控:To enable this type of scenario the language will be introducing a new constraint: unmanaged:

void Hash<T>(T value) where T : unmanaged

只有符合 c # 語言規格中非受控型別定義的型別,才能符合這個條件約束。另一種查看方法的方法是,如果型別也可以當做指標使用,則它會滿足非受控條件約束。This constraint can only be met by types which fit into the unmanaged type definition in the C# language spec. Another way of looking at it is that a type satisfies the unmanaged constraint if it can also be used as a pointer.

Hash(new Point()); // Okay 
Hash(42); // Okay
Hash("hello") // Error: Type string does not satisfy the unmanaged constraint

具有未受管理之條件約束的類型參數可以使用非受控類型可用的所有功能:指標、固定等等。Type parameters with the unmanaged constraint can use all the features available to unmanaged types: pointers, fixed, etc ...

void Hash<T>(T value) where T : unmanaged
    // Okay
    fixed (T* p = &value) 

此條件約束也可讓結構化資料和位元組資料流程之間有有效率的轉換。This constraint will also make it possible to have efficient conversions between structured data and streams of bytes. 這是網路堆疊和序列化層級常見的作業:This is an operation that is common in networking stacks and serialization layers:

Span<byte> Convert<T>(ref T value) where T : unmanaged 

這類常式很有利,因為它們在編譯時期可證明安全,而且可以免費進行配置。Such routines are advantageous because they are provably safe at compile time and allocation free. 目前,Interop 作者無法 (這項作業,即使它是在效能關鍵) 的層級。Interop authors today can not do this (even though it's at a layer where perf is critical). 相反地,他們必須依賴配置具有昂貴執行時間檢查的常式,以確認值的管理是否正確。Instead they need to rely on allocating routines that have expensive runtime checks to verify values are correctly unmanaged.

詳細設計Detailed design

語言將引進名為的新條件約束 unmanagedThe language will introduce a new constraint named unmanaged. 為了滿足這個條件約束,型別必須是一個結構,而且該型別的所有欄位都必須屬於下列其中一個類別:In order to satisfy this constraint a type must be a struct and all the fields of the type must fall into one of the following categories:

  • 具有類型、、、、、、、、、、、、 sbyte byte short ushort int uint long ulong char float double decimal bool IntPtrUIntPtrHave the type sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, IntPtr or UIntPtr.
  • 為任何 enum 類型。Be any enum type.
  • 這是指標類型。Be a pointer type.
  • 這是滿足條件約束的使用者定義結構 unmanagedBe a user defined struct that satisfies the unmanaged constraint.

編譯器產生的實例欄位(例如支援自動實作為的屬性)也必須符合這些條件約束。Compiler generated instance fields, such as those backing auto-implemented properties, must also meet these constraints.

例如:For example:

// Unmanaged type
struct Point 
    int X;
    int Y {get; set;}

// Not an unmanaged type
struct Student 
    string FirstName;
    string LastName;

unmanaged條件約束不能與 struct 或合併 class new()The unmanaged constraint cannot be combined with struct, class or new(). 這種限制衍生自 unmanaged 暗示 struct 其他條件約束並不合理的事實。This restriction derives from the fact that unmanaged implies struct hence the other constraints do not make sense.

unmanaged 條件約束不會由 CLR 強制執行,只能由語言強制執行。The unmanaged constraint is not enforced by CLR, only by the language. 若要防止其他語言使用錯誤,具有此條件約束的方法會受到 mod 需求的保護。這可防止其他語言使用非受控類型的類型引數。To prevent mis-use by other languages, methods which have this constraint will be protected by a mod-req. This will prevent other languages from using type arguments which are not unmanaged types.

unmanaged條件約束中的 token 不是關鍵字,也不是內容關鍵字。The token unmanaged in the constraint is not a keyword, nor a contextual keyword. 相反地,它會在 var 該位置進行評估,而且會:Instead it is like var in that it is evaluated at that location and will either:

  • 系結至名為的使用者定義或參考型別 unmanaged :這會被視為處理任何其他命名類型條件約束。Bind to user defined or referenced type named unmanaged: This will be treated just as any other named type constraint is treated.
  • 系結至無類型:這會被解釋為 unmanaged 條件約束。Bind to no type: This will be interpreted as the unmanaged constraint.

如果有一個名為的型別 unmanaged ,而且在目前的內容中沒有限定性,就沒有任何方法可以使用 unmanaged 條件約束。In the case there is a type named unmanaged and it is available without qualification in the current context, then there will be no way to use the unmanaged constraint. 這會將功能 var 和使用者定義類型的相關規則與相同名稱相關。This parallels the rules surrounding the feature var and user defined types of the same name.


這項功能的主要缺點是,它提供少數的開發人員:通常是低層級的程式庫作者或架構。The primary drawback of this feature is that it serves a small number of developers: typically low level library authors or frameworks. 因此,對少數開發人員來說,它會花費寶貴的語言時間。Hence it's spending precious language time for a small number of developers.

但是這些架構通常是大部分 .NET 應用程式的基礎。Yet these frameworks are often the basis for the majority of .NET applications out there. 因此,在此層級獲勝的效能/正確性可能會對 .NET 生態系統造成 ripple 影響。Hence performance / correctness wins at this level can have a ripple effect on the .NET ecosystem. 這項功能可讓您只考慮有限制的物件。This makes the feature worth considering even with the limited audience.


有幾個替代方案可以考慮:There are a couple of alternatives to consider:

  • 現狀:此功能不會在其本身的優點上調整,而開發人員會繼續使用隱含的加入宣告行為。The status quo: The feature is not justified on its own merits and developers continue to use the implicit opt in behavior.


中繼資料標記法Metadata Representation

F # 語言會編碼簽章檔案中的條件約束,這表示 c # 無法重複使用其標記法。The F# language encodes the constraint in the signature file which means C# cannot re-use their representation. 必須為這個條件約束選擇新的屬性。A new attribute will need to be chosen for this constraint. 此外,具有這個條件約束的方法必須受到 mod 需求的保護。Additionally a method which has this constraint must be protected by a mod-req.

可管理的與非受控Blittable vs. Unmanaged

F # 語言具有非常類似的 功能 ,其使用非受控關鍵字。The F# language has a very similar feature which uses the keyword unmanaged. 可集中的名稱來自于 Midori 使用。The blittable name comes from the use in Midori. 您可能會想要在此查看優先順序並改用非受控。May want to look to precedence here and use unmanaged instead.

解決 方式語言決定使用非受控Resolution The language decide to use unmanaged


是否需要更新驗證器/執行時間,才能瞭解泛型型別參數的指標使用方式?Does the verifier / runtime need to be updated to understand the use of pointers to generic type parameters? 也可以直接使用而不需要變更嗎?Or can it simply work as is without changes?

解決 方式不需要任何變更。Resolution No changes needed. 所有指標類型都只是無法驗證的。All pointer types are simply unverifiable.

設計會議Design meetings