最优雅的XML序列化Color结构

Dia*_*cus 36 c# xml-serialization

一个问题让我足以在Stack Overflow上注册.目前,如果我想将Color to XML string序列化为命名颜色,或者#rrggbb,或者#aarrggbb,我这样做:

[XmlIgnore()]
public Color color;

[XmlElement(ElementName = "Color")]
public String color_XmlSurrogate
{
  get { return MyColorConverter.SetColor(color); }
  set { color = MyColorConverter.GetColor(value); }
}
Run Code Online (Sandbox Code Playgroud)

MyColorConverter是按照我喜欢的方式进行序列化.但所有这一切感觉就像一个kludge,有额外的领域和所有.有没有办法让它在更少的行中工作,可能将TypeDescriptor与与XML相关的C#属性连接起来?

bvj*_*bvj 62

这是我用于Color在XML中序列化结构的东西.Color在我看来,这比遮蔽主要财产更好.欢迎任何建议.

XmlColor班主要依赖implicit operator语言功能来提供关键数据tranformations.没有这个,这个班基本没用.添加了其他功能以完善课程.

XmlColor助手还提供了一个方便的方法来分离颜色分量.我添加了Alpha属性来显示这个.请注意,Alpha如果组件一直转动到255,则不会将其序列化.

反序列化Web颜色值组合了Alpha当前存储在实例中的值.解析属性的顺序无关紧要.如果AlphaXML源中缺少该属性,则将使用实例组件值来设置Alpha级别.这可以说是错误的; 但是,在XML序列化的情况下,XmlColor类将初始化为Color.Black设置Alpha为255.

我正在使用VS2010环境并构建.Net 4.我不知道代码与以前版本的兼容性如何.

这是一个应该序列化为XML的示例属性:

    [XmlElement(Type=typeof(XmlColor))]
    public Color MyColor { get; set; }
Run Code Online (Sandbox Code Playgroud)

这是XmlColor辅助类:

public class XmlColor
{
    private Color color_ = Color.Black;

    public XmlColor() {}
    public XmlColor(Color c) { color_ = c; }


    public Color ToColor()
    {
        return color_;
    }

    public void FromColor(Color c)
    {
        color_ = c;
    }

    public static implicit operator Color(XmlColor x)
    {
        return x.ToColor();
    }

    public static implicit operator XmlColor(Color c)
    {
        return new XmlColor(c);
    }

    [XmlAttribute]
    public string Web
    {
        get { return ColorTranslator.ToHtml(color_); }
        set {
            try
            {
                if (Alpha == 0xFF) // preserve named color value if possible
                    color_ = ColorTranslator.FromHtml(value);
                else
                    color_ = Color.FromArgb(Alpha, ColorTranslator.FromHtml(value));
            }
            catch(Exception)
            {
                color_ = Color.Black;
            }
        }
    }

    [XmlAttribute]
    public byte Alpha
    {
        get { return color_.A; }
        set { 
            if (value != color_.A) // avoid hammering named color if no alpha change
                color_ = Color.FromArgb(value, color_); 
        }
    }

    public bool ShouldSerializeAlpha() { return Alpha < 0xFF; }
}
Run Code Online (Sandbox Code Playgroud)

  • 您可以将类剥离为隐式运算符和单个可发布属性.该属性如何序列化完全取决于您.我注意到,无论alpha值如何,都要使用十六进制字符串调用Argb方法.我选择XmlAttribute来避免子元素.你可以考虑一个"ARGB"XmlAttribute并使用Argb方法强制4个组件的十六进制字符串.毫无疑问,如果你发现它有用,你可以挤进Color属性. (4认同)
  • @bvj,太糟糕了我不能给你这个奖励:) (3认同)
  • 我喜欢这个!如果它有效,那就是.我使用VS2008和.NET 3.5,所以我需要在将来的某个时间检查它.是否有理由使用ToColor/FromColor而不是某些Color属性?这可以重新编码为只有一个xml字符串作为序列化值吗?我希望这是结果:`<Color> #aarrggbb </ Color>` (2认同)
  • 这是天才.现在我只需要在我的代码中添加一个`[XmlElement(Type = typeof(XmlColor))]`属性.真的是最优雅的解决方案. (2认同)
  • 如果你正在使用WPF颜色(或将你的WinForms颜色转换为WPF),自动序列化将起作用,但它有点难看(给你一个A,R,G,B,ScA,ScR,ScG的XML元素)和每个ScB).但是通过对bvj解决方案稍加修改的版本,只需将`ColorTranslator.ToHtml()`替换为`color_.ToString()`和`ColorTranslator.FromHtml()`并使用`ColorConverter.FromString()`即可获得更好的输出. .结果将以"#FF000000"的形式存储,因此您甚至不需要处理单独的Alpha值. (2认同)

小智 19

我相信下面我有一个更简单的解决方案.忽略颜色序列化并保存颜色并将其作为简单的32位ARGB数据加载.

[XmlIgnore]
public Color BackColor { get; set; }

[XmlElement("BackColor")]
public int BackColorAsArgb
{
    get { return BackColor.ToArgb();  }
    set { BackColor = Color.FromArgb(value); }
}
Run Code Online (Sandbox Code Playgroud)

  • 我很好奇你想避免"替代财产"的原因是什么? (4认同)
  • 这个解决方案仍然存在我想避免的问题,即代理属性. (3认同)

Mar*_*ell 5

痛苦,不是吗?XmlSerializer除非你实施IXmlSerializable(我推荐),你可以做的就是这一切.选项:

  • 坚持这一点,但也标记color_XmlSurrogate[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]- 这将阻止它出现在大多数数据绑定视图中,并在代码编辑器中引用您的程序集作为DLL
  • use DataContractSerializer,它支持私有属性(但支持xml属性;你不能赢...)

顺便说一下,我有color一个属性,而不是一个字段:

[XmlIgnore]
public Color Color {get;set;}
Run Code Online (Sandbox Code Playgroud)