具有多个零值问题的标志枚举(TextFormatFlags)

时间:2009-12-07 20:18:58

标签: .net enums flags

在尝试编写自定义控件时,我遇到了System.Windows.Forms.TextFormatFlags枚举与Visual Studio(2005/2008)编辑器结合的问题。这个问题的原因似乎来自这个枚举有多个成员映射到零值的事实。选择任何这些成员(GlyphOverhangPadding,Left,Default,Top)会导致编辑器将属性设置为

this.customControl.TextFormatFlags = System.Windows.Forms.TextFormatFlags.GlyphOverhangPadding;

代码按预期编译。但是,从编辑器的属性网格中选择任何非零成员(例如“右”)会产生以下结果:

this.customControl.TextFormatFlags = System.Windows.Forms.TextFormatFlags.Left, Default, Top, Right;

显然这不会编译。选择多个非零成员(通过UITypeEditor,例如“Right | Bottom”)会产生以下结果:

this.customControl.TextFormatFlags = ((System.Windows.Forms.TextFormatFlags)((System.Windows.Forms.TextFormatFlags.Left, Default, Top, Right | System.Windows.Forms.TextFormatFlags.Left, Default, Top, Bottom)));

如您所见,编辑器将四个零值成员中的三个添加到任何选定的项目中。

如果您希望重现此问题:

  • 在Visual Studio 2005/2008(Windows窗体应用程序)中创建新项目
  • 向项目添加自定义控件。
  • 将私有字段和公共属性添加到新类:

    私有TextFormatFlags tff = TextFormatFlags.Default;

    public TextFormatFlags TFFProperty {     得到{return this.tff; }     设置{this.tff = value; } }

  • 编译代码

  • 在设计器中打开Form1并向其添加CustomControl1
  • 代码编译正常
  • 现在在编辑器的PropertyGrid
  • 中打开CustomControl1的属性
  • 您应该在“杂项”部分
  • 下看到TFFProperty
  • 该属性提供了多个值,其中大多数都包含逗号。
  • 使用逗号选择任何值(例如“Left,Default,Top,Horizo​​ntalCenter)会导致不可编辑的代码

如果使用Flags属性创建自己的枚举并添加多个映射到零的成员(这是一种格式错误的标记枚举?),也会发生同样的情况。我已经验证这不是我正在使用的UITypeEditor的错误(不使用UITypeEditor也会出现同样的问题)。我试图用转换器来解决这个问题,到目前为止还没有成功。如果有人对如何解决这个问题有任何想法,我会很高兴听到他们。

1 个答案:

答案 0 :(得分:3)

我使用Reflector检查了System.ComponentModel.Design.Serialization命名空间中的各个类,我认为CodeDom序列化器有点顽皮。

枚举由EnumCodeDomSerializer.Serialize处理,其目的是获取枚举并将其转换为代表您在设计器文件中看到的System.CodeDom.CodeExpression对象。

此方法正确使用CodeBinaryOperatorExpression来处理表达式的|方面。但是,对于单个枚举值,它使用Enum.ToString通过EnumTypeConverter并将结果字符串直接粘贴到表达式树中。

我认为Enum.ToString是你所看到的最终原因:

  

如果多个枚举成员具有相同的基础值,并且您尝试根据其基础值检索枚举成员名称的字符串表示形式,则您的代码不应对该方法将返回的名称做出任何假设。

诚然,Enum.ToString上的MSDN页面没有谈论逗号,但依赖Enum.ToString作为有效C#表达式的输出似乎仍然不安全。

我不确定这对你的控制意味着什么:

  • 显然,您可以为TextFormatFlags定义自己的替代品,并且无需重复的零标记
  • 您可以使用自定义类型转换器来破解它,也许可以转换为InstanceDescriptor。这使您可以更好地控制设计器生成的代码中显示的内容。
  • 您可能会向设计器序列化程序公开int,但向属性网格公开TextFormatFlags

修改: The comma-separated list behaviour of Enum.ToString is in fact documented