【问题标题】:Is System.Reflection.TypeAttributes a sick enum type with the FlagsAttribute? [closed]System.Reflection.TypeAttributes 是带有 FlagsAttribute 的病态枚举类型吗? [关闭]
【发布时间】:2017-02-16 14:43:03
【问题描述】:

枚举类型System.Reflection.TypeAttributes 显得相当病态。它带有[Flags] 属性,并且对于常数零有不少于四个 的同义词。来自 Visual-Studio 生成的“元数据”:

#region Assembly mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\mscorlib.dll
#endregion

using System.Runtime.InteropServices;

namespace System.Reflection
{
  //
  // Summary:
  //     Specifies type attributes.
  [ComVisible(true)]
  [Flags]
  public enum TypeAttributes
  {
    //
    // Summary:
    //     Specifies that the class is not public.
    NotPublic = 0,
    //
    // Summary:
    //     Specifies that class fields are automatically laid out by the common language
    //     runtime.
    AutoLayout = 0,
    //
    // Summary:
    //     Specifies that the type is a class.
    Class = 0,
    //
    // Summary:
    //     LPTSTR is interpreted as ANSI.
    AnsiClass = 0,

    // (followed by non-zero members...)

为什么有人会在带有FlagsAttribute 的枚举类型中使用四个名称作为零?看起来真的很疯狂。

看看后果:

var x = default(System.Reflection.TypeAttributes);     // 0
var sx = x.ToString();                                 // "NotPublic"
var y = (System.Reflection.TypeAttributes)(1 << 20);   // 1048576
var sy = y.ToString();                                 // "AutoLayout, AnsiClass, Class, BeforeFieldInit"

这里x的字符串表示,类型的零值,变成"NotPublic"。而非零y 的字符串表示变为"AutoLayout, AnsiClass, Class, BeforeFieldInit"。关于y,请注意它只有一个位集(1&lt;&lt;20),而名称BeforeFieldInit 就恰好说明了该位。所有其他三个名称 AutoLayout, AnsiClass, Class, 对值的贡献为零。

发生了什么事?

为什么要这样设计?

【问题讨论】:

  • @ChrisBint 我不确定你的意思?
  • 这些名称来自 CLI 规范,Ecma 335。它们使枚举定义尽可能接近规范,这并没有什么不好的。程序集元数据首先过于紧凑,在一个字段中尽可能多地打包选项。现在有点不定型也很重要,他们从来没有试图让它变得友好。它只对非常低级的程序集转储代码很重要,而不是盲目依赖 ToString() 的那种代码。

标签: c# .net enums base-class-library enum-flags


【解决方案1】:

ToString() 表示在很大程度上无关紧要

当某些选项是非二进制时,这种模式很常见;例如,有 3 个可能的选项。在那种情况下,您可能会指定 2 位来承载这 3 个选项(留下 4 个未使用),并且“默认”选项将(逻辑上)00。这意味着是的,0 会有多个同义词。

注意:这可能发生在纯二元选项中,如果枚举作者想让它更明确 - 因为调用者不需要知道哪些是“on”,哪些是“关闭”。

基本上不用担心ToString()

【讨论】:

  • AutoLayout 是什么意思,举个例子?如果我测试typeof(TimeSpan).Attributes.HasFlag(TypeAttributes.AutoLayout),结果为真。所以TimeSpan 有布局“自动”,对吧? typeof(TimeSpan).Attributes.HasFlag(TypeAttributes.SequentialLayout) 也是如此,所以 TimeSpan 也有布局顺序,对吧?
  • @JeppeStigNielsen (注意:之前已删除)我认为问题在于ToString()。同样,这是一个三元组——自动的、显式的或顺序的。 ToString() 弄错了,天真的测试也是如此。这里的 正确 测试是 val &amp; 24 - 是 0 (AutoLayout)、8 (SequentialLayout) 还是 16 (ExplicitLayout)? HasFlag 仅适用于二进制标志,而这不是。 IMO 这是“95%”的事情。您使用的 API 是为 95% 的护理而设计的,这不是。 (其实还有LayoutMask = 24,是explicit的特例,所以:有点3.5的options表示)
  • 我怎么知道“auto”是这三个的神奇案例?他们也可以选择explicit=0、sequential=8、auto=16?在这种情况下,我将无法直接测试“显式”(因为该值为零)。他们确实有一个名字LayoutMask 的总和8 | 16
  • @JeppeStigNielsen 哈哈,是的,看起来我误解了LayoutMask 一个,它纯粹是为您所询问的确切测试而设计的。至于如何知道它不是二进制标志集;我猜是文档,但在这种情况下不是很清楚。碰巧我昨天写了这些违规行为之一 - 我希望我的 cmets 比 MSDN 的更好! github.com/mgravell/Channels.Http2/blob/master/src/…(见:public enum HeaderOptions)。
  • 对我来说,唯一明智的做法是为三个选项中的每一个使用一个位,例如AutoLayout=4, SequentialLayout = 8, ExplicitLayout = 16,。如果您愿意,您仍然可以为组合(“掩码”)4 | 8 等命名。如果我阅读了您上面的答案,我会觉得您认为这里的设计没有问题?你真的这么认为吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-14
  • 2018-03-06
  • 2019-08-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多