我希望在部分类上的类级别上使用unsafe
修饰符时出现某种行为,
我一直在研究一个较大的包装器,出于理智的考虑,使用partial
修饰符将其拆分为多个文件。包装器大量使用unsafe
指针,因此我选择仅在类级别声明它以覆盖其中的所有内容。
public static unsafe partial class Ruby
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static VALUE CLASS_OF(VALUE obj) => ((RBasic*) obj)->klass;
}
在另一个文件中:
public static unsafe partial class Ruby
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void* DATA_PTR(VALUE obj) => ((RData*) obj)->data;
}
每个部分声明都需要unsafe
修饰符,以便“允许”和编译不安全的代码,这是可以理解的,我希望部分类的类声明需要完全匹配。
但是使用这种逻辑,我也可以拥有另一个不是unsafe
的文件:
[SuppressUnmanagedCodeSecurity]
public static partial class Ruby
{
[DllImport(RUBY_LIBRARY, CallingConvention = CallingConvention.Cdecl)]
public static extern VALUE rb_ivar_get(VALUE obj, ID name);
}
在这里,我不使用unsafe
修饰符,并且完全可以接受(显然,该文件中没有不安全的代码)。
我希望澄清为什么允许这样做。每个子类的类声明不应该完全匹配吗?不允许更改/排除任何其他类修饰符,例如private
,public
,abstract
等,因此unsafe
为何还可以。我认为该行为似乎不一致。我的猜测是,编译器会以某种方式在不同的上下文中运行它,但这只是我的推测,并希望对此比我有更多知识的人能提供一些启发。
答案 0 :(得分:11)
您关于需要一致性的修饰符的断言有些偏离。例如,这是完全有效的:
public abstract partial class Foo { }
partial class Foo { }
Foo
将表示一个抽象类,因为其中的一部分被声明为抽象。有关部分类的类修饰符的规则,请参见规范的第10.2.2节。以下是与unsafe
局部类有关的文本:
在部分类型声明上使用unsafe修饰符时,只有该特定部分才被视为不安全上下文(第18.1节)。
将sealed
或abstract
应用于部分类时,该类的所有部分都被视为sealed
或abstract
。但是,不能两者兼有。
实际上,可访问性是部分上唯一的类修饰符,必须在所有部分之间保持一致,但不需要在所有部分中都设置。
当部分类型声明包含可访问性规范(公共,受保护,内部和私有修饰符)时,它必须与所有包含可访问性规范的其他部分一致。如果部分类型的任何部分都不包含可访问性规范,则将为该类型提供适当的默认可访问性(第3.5.1节)。
这基本上可以归结为不允许同时声明public partial class Bar
和internal partial class Bar
,因为各部分之间的可访问性变得不一致。声明没有可访问性的其他部分将默认为已声明的可访问性,或者是规范第3.5.1节中概述的规则所指定的默认值。
注意:我引用的规范部分来自Visual Studio 2017随附的规范版本。
ECMA-334参考如下:
23.2:
在部分类型声明(第15.2.7节)上使用unsafe修饰符时,仅该特定部分为 被认为是不安全的环境。
15.2.2.1:
如果部分类型声明(第15.2.7节)包含可访问性规范(通过公众, 受保护的,内部的和私有的修饰符),则该规范应与所有其他 包括一个可访问性规范。如果部分类型的任何部分都不包含可访问性规范,则 类型提供适当的默认可访问性(第8.5.2节)。
15.2.2.2和15.2.2.3具有有关abstract
和sealed
修饰符的规则。