具有多个零值问题的标志枚举(TextFormatFlags) [英] Flags enumeration with multiple zero values problem (TextFormatFlags)

查看:128
本文介绍了具有多个零值问题的标志枚举(TextFormatFlags)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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

  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窗体应用程序)

  • 向项目添加自定义控件。

  • 添加私有字段和公共属性到新课程:



    private TextFormatFlags tff = TextFormatFlags.Default;



    public TextFormatFlags TFFProperty
    {
    get {return this.tff; }
    set {this.tff = value;
    }


  • 编译代码


  • 在设计器中打开Form1,并添加CustomControl1

  • 代码编译良好
  • 现在在编辑器的PropertyGrid

  • 中打开CustomControl1的属性应该在杂项部分看到TFFProperty

  • 该属性提供了几个值,其中大部分包含一个逗号。

  • 选择任何值使用逗号(例如左,默认,顶部,水平中心)导致不可编译的代码



同样的情况,如果您创建自己的枚举与Flags属性并添加多个成员映射为零(这是一种格式不正确的标志枚举?)我已经证实这不是我使用的UITypeEditor的错误(同样的问题发生在不使用UITypeEditor)我试图绕过一个转换器的问题,到目前为止没有成功如果有人有任何想法如何解决这个问题,我会很高兴h

解决方案

我通过 System.ComponentModel.Design.Serialization 命名空间使用反射器,我认为CodeDom序列化程序有点调皮。



枚举由 EnumCodeDomSerializer.Serialize ,其目的是取一个枚举,并将其转换成代表您在设计器文件中看到的 System.CodeDom.CodeExpression 对象。 / p>

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



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


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

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



我不知道这对你的控制是什么意思:




  • 很明显,您可以定义自己替换的 TextFormatFlags ,而不需要重复的零标记

  • 您可以可以使用自定义类型转换器,也可以将其转换为 InstanceDescriptor 。这样可以更好地控制设计师生成的代码中的内容。

  • 您可能会向设计者公开一个 int 序列化器,但是一个 TextFormatFlags 到属性网格



编辑: / strong> 枚举的逗号分隔列表行为。事实上,ToString 记录了


While trying to write a custom control I've come across a problem with the System.Windows.Forms.TextFormatFlags enum in combination with the Visual Studio (2005/2008) editor. The reason for this problem seems to come from the fact that this enum has multiple members which map to a zero value. Selecting any of these members (GlyphOverhangPadding, Left, Default, Top) results in the editor setting the property to

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

The code compiles, as expected. However, selecting any non-zero member (e.g. "Right") from the editor's property grid results in the following:

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

Obviously this does not compile. Selecting more than one non-zero member (Through a UITypeEditor, e.g. "Right | Bottom") results in the following:

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

As you can see, the editor adds three of the four zero-value members to any selected item.

If you wish to reproduce this issue:

  • Create a new project in Visual Studio 2005/2008 (Windows Forms Application)
  • Add a Custom Control to the project.
  • Add a private field and public property to the new class:

    private TextFormatFlags tff = TextFormatFlags.Default;

    public TextFormatFlags TFFProperty { get { return this.tff; } set { this.tff = value; } }

  • Compile the code

  • Open Form1 in the designer and add CustomControl1 to it
  • The code compiles fine
  • Now open the properties of CustomControl1 in the editor's PropertyGrid
  • You should see the TFFProperty under the "Misc" section
  • The property offers several values, most of which contain a comma.
  • Selecting any of the values with a comma (e.g. "Left, Default, Top, HorizontalCenter) results in non compilable code

The same happens if you create your own enum with the Flags attribute and add more than one member mapped to zero (which is a kind of malformed flags enum?). I've verified that this is not a bug with the UITypeEditor I'm using (The same problem occurs without using the UITypeEditor). I've tried to circumvent the problem with a Converter, so far without success. If anyone has any ideas on how to solve this problem I'd be glad to hear them.

解决方案

I checked through the various classes in the System.ComponentModel.Design.Serialization namespace using Reflector, and I think the CodeDom serializer is being a bit naughty.

Enums get handled by EnumCodeDomSerializer.Serialize, whose purpose is to take an enum and turn it into a System.CodeDom.CodeExpression object that represents what you see in the designer file.

This method correctly uses CodeBinaryOperatorExpression to handle the | aspect of the expression. However, for the individual enum values, it uses Enum.ToString via EnumTypeConverter and sticks the resulting string directly into the expression tree.

I think Enum.ToString is the ultimate cause of what you're seeing:

If multiple enumeration members have the same underlying value and you attempt to retrieve the string representation of an enumeration member's name based on its underlying value, your code should not make any assumptions about which name the method will return.

Admittedly the MSDN page on Enum.ToString doesn't talk about the commas, but it still doesn't seem safe to rely on the output of Enum.ToString being a valid C# expression.

I'm not sure what this means for your control:

  • Clearly you can define your own replacement for TextFormatFlags and do it without the duplicated zero flags
  • You may be able to hack it with a custom type converter, maybe one that converts to InstanceDescriptor. This gives you a little more control over what appears in the designer-generated code.
  • You could possibly expose an int to the designer serializer but a TextFormatFlags to the property grid

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

这篇关于具有多个零值问题的标志枚举(TextFormatFlags)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆