アンマネージ型制約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# で低レベルの相互運用コードを簡単に作成できるようにすることです。The primary motivation is to make it easier to author low level interop code in C#. アンマネージ型は相互運用コードの中核となる構成要素の1つですが、ジェネリックのサポートがないため、すべてのアンマネージ型で再利用可能なルーチンを作成することはできません。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 iff 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 

このようなルーチンは、コンパイル時には安全であり、割り当てが provably されるため、便利です。Such routines are advantageous because they are provably safe at compile time and allocation free. 現在、相互運用の作成者はこれを行うことはできません (パフォーマンスが重要なレイヤーにある場合でも)。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

この言語では、という名前の新しい制約が導入され unmanaged ます。The 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 IntPtr UIntPtr ます。Have 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.

制約は、CLR によって適用されるのでは unmanaged なく、言語によってのみ適用されます。The unmanaged constraint is not enforced by CLR, only by the language. 他の言語による mis の使用を防ぐために、この制約を持つメソッドは 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制約内のトークンがキーワードではなく、コンテキストキーワードでもありません。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.
  • No type にバインドする: これは制約として解釈され unmanaged ます。Bind to no type: This will be interpreted as the unmanaged constraint.

という名前の型があり、 unmanaged 現在のコンテキストでは修飾なしで使用できる場合、制約を使用する方法はありません unmanagedIn 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 エコシステムに波及効果を与えることができます。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 とアンマネージBlittable vs. Unmanaged

F # 言語には、アンマネージキーワードを使用する非常によく似た機能があります。The F# language has a very similar feature which uses the keyword unmanaged. Blittable 名は、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