C# · 12月 23, 2021

c# – 为什么使用“部分”时类级“不安全”修饰符不一致?

我已经注意到在类级别对部分类使用unsafe修饰符时的某种行为,我希望得到一些澄清.

我一直在研究一个相当大的包装器,为了理智,我使用partial修饰器分割多个文件.包装器大量使用不安全的指针,因此我选择在类级别上简单地声明它以覆盖其中的所有内容.

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修饰符,以便“允许”和编译不安全的代码,这是可以理解的,我希望部分类的类声明需要完全匹配.

但是使用这个逻辑,我也被允许有另一个不安全的文件:

[SuppressUnmanagedCodeSecurity]public static partial class Ruby{ [DllImport(RUBY_LIBRARY,CallingConvention = CallingConvention.Cdecl)] public static extern VALUE rb_ivar_get(VALUE obj,ID name);}

在这里,我不使用unsafe修饰符,它是完全可以接受的(显然这个文件中没有不安全的代码).

我是什么希望得到澄清为什么这允许.每个分类的类声明不应该完全匹配吗?不允许更改/排除任何其他类修饰符,例如私有,公共,抽象等,所以为什么这是不安全的.在我看来,这种行为似乎不一致.我的猜测是,它在不同的情况下由编译器在不同的上下文中运行,但这只是我的猜想,并且希望有人比我更了解这个可能会有所启发.

解决方法 关于需要一致性的修饰语的断言有点过时了.例如,这是完全有效的: public abstract partial class Foo { }partial class Foo { }

Foo将表示一个抽象类,因为它的一个部分被声明为abstract.有关部分类的类修饰符的规则可以在规范的10.2.2节中找到.这是与不安全的部分类相关的文本:

When the unsafe modifier is used on a partial type declaration,only that particular part is considered an unsafe context (§18.1).

当密封或抽象应用于部分类时,该类的所有部分都被认为是密封的或抽象的.但它不能同时存在.

实际上,可访问性是partials上唯一必须在所有部分之间保持一致的类修饰符,但不需要在所有部分中设置.

When a partial type declaration includes an accessibility specification (the public,protected,internal,and private modifiers) it must agree with all other parts that include an accessibility specification. If no part of a partial type includes an accessibility specification,the type is given the appropriate default accessibility (§3.5.1).

这基本上归结为不允许声明公共部分类Bar和内部部分类Bar,因为部件之间的可访问性变得不一致.声明没有可访问性的其他部分将默认为已声明的可访问性,或默认值为规范3.5.1节中规定的规则.

注意:我引用的规范部分来自Visual Studio 2017附带的规范版本.

ECMA-334参考文献如下:

23.2:

When the unsafe modifier is used on a partial type declaration (§15.2.7),only that particular part is
considered an unsafe context.

15.2.2.1:

When a partial type declaration (§15.2.7) includes an accessibility specification (via the public,
protected,and private modifiers),that specification shall agree with all other parts that
include an accessibility specification. If no part of a partial type includes an accessibility specification,the
type is given the appropriate default accessibility (§8.5.2).

15.2.2.2和15.2.2.3有关于抽象和密封修饰符的规则.