非托管类型约束Unmanaged type constraint

总结Summary

非托管约束功能将向 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.

动机Motivation

主要动机是使在 c # 中编写低级别互操作代码变得更加容易。The primary motivation is to make it easier to author low level interop code in C#. 非托管类型是互操作代码的核心构建基块之一,但缺乏泛型支持将无法跨所有非托管类型创建可重复使用的例程。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 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约束中的标记不是关键字,也不是上下文关键字。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.

缺点Drawbacks

此功能的主要缺点是它提供少量的开发人员:通常是低级别库作者或框架。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. 因此,在此级别上 wins 会对 .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.

备选方法Alternatives

有几种方法可以考虑: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.

问题Questions

元数据表示形式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

Verifier

验证程序/运行时是否需要更新以了解如何使用指向泛型类型参数的指针?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

n/an/a