C# 将XML值反序列化到枚举时处理额外空间

C# 将XML值反序列化到枚举时处理额外空间,c#,xml,serialization,enums,C#,Xml,Serialization,Enums,我一直在想是否有可能做到这一点 如果XML响应具有需要映射到枚举的不正确值,那么这将非常有帮助 我要特别处理的情况是,一个期望值有一个尾随空格,而枚举期望它没有尾随空格 XML: 类别: 我已经研究过使用自定义属性(而不是“XmlEnum”)来修剪值,但在反序列化过程中似乎没有达到该属性 是否有方法在反序列化之前/期间修剪XML值(如果需要),以便将值正确映射到枚举 - 我应该补充一点,我不能对XML的发送方式做任何更改,我只能处理响应 此外,只需将属性参数更改为[XmlEnum(“EnumVa

我一直在想是否有可能做到这一点

如果XML响应具有需要映射到枚举的不正确值,那么这将非常有帮助

我要特别处理的情况是,一个期望值有一个尾随空格,而枚举期望它没有尾随空格

XML: 类别: 我已经研究过使用自定义属性(而不是“XmlEnum”)来修剪值,但在反序列化过程中似乎没有达到该属性

是否有方法在反序列化之前/期间修剪XML值(如果需要),以便将值正确映射到枚举

-

我应该补充一点,我不能对XML的发送方式做任何更改,我只能处理响应


此外,只需将属性参数更改为[XmlEnum(“EnumValue”)]即可解决问题,但这并不令人满意,因为XML值可能会在以后更改。

如果XML不是很大和/或性能不太可能成为问题,在使用
XmlSerializer
进行反序列化之前,您可以简单地用LINQ解析为XML,并修复任何不正确的值:

var doc = XDocument.Parse(xml);

foreach (var bar in doc.Descendants("Bar"))
{
    bar.Value = bar.Value.Trim();
}

using (var reader = doc.CreateReader())
{
    var obj = serializer.Deserialize(reader);
}
请试试这个:

public class Foo
{
    [XmlIgnore]
    public MyEnum myEnum { get; set; }

    [XmlElement("Bar")]
    [EditorBrowsable(EditorBrowsableState.Never)]
    public string _myEnum
    {
        get { return myEnum.ToString(); }
        set { myEnum = (MyEnum)Enum.Parse(typeof(MyEnum), value.Trim()); }
    }
}

不幸的是,没有针对未知枚举值触发的事件允许您替换自己的解析算法。此外,不设置
AttributeUsage.AllowMultiple=true
,因此不能添加具有前导空格和尾随空格各种组合的多个枚举别名

一种可能的解决方法是手动执行和解析。另一种方法是添加封装枚举的包装结构来处理解析:

public class Foo
{
    [XmlIgnore]
    public MyEnum myEnum { get; set; }

    [XmlElement("Bar")]
    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DebuggerBrowsable(DebuggerBrowsableState.Never)]
    public XmlEnumWrapper<MyEnum> myEnumXml { get { return myEnum; } set { myEnum = value; } }
}

public struct XmlEnumWrapper<TEnum> : IEquatable<XmlEnumWrapper<TEnum>> where TEnum : struct, IConvertible, IComparable, IFormattable
{
    TEnum value;

    public XmlEnumWrapper(TEnum value)
    {
        this.value = value;
    }

    public static implicit operator TEnum(XmlEnumWrapper<TEnum> wrapper)
    {
        return wrapper.Value;
    }

    public static implicit operator XmlEnumWrapper<TEnum>(TEnum anEnum)
    {
        return new XmlEnumWrapper<TEnum>(anEnum);
    }

    public static bool operator ==(XmlEnumWrapper<TEnum> first, XmlEnumWrapper<TEnum> second)
    {
        return first.Equals(second);
    }

    public static bool operator !=(XmlEnumWrapper<TEnum> first, XmlEnumWrapper<TEnum> second)
    {
        return !first.Equals(second);
    }

    [XmlIgnore]
    public TEnum Value { get { return value; } private set { this.value = value; } }

    [XmlText]
    public string ValueString
    {
        get
        {
            return Value.ToString();
        }
        set
        {
            // See here if one needs to parse XmlEnumAttribute attributes
            // http://stackoverflow.com/questions/3047125/retrieve-enum-value-based-on-xmlenumattribute-name-value
            value = value.Trim();
            Value = (TEnum)Enum.Parse(typeof(TEnum), value, false);
        }
    }

    #region IEquatable<XmlEnumWrapper<TEnum>> Members

    public bool Equals(XmlEnumWrapper<TEnum> other)
    {
        return EqualityComparer<TEnum>.Default.Equals(Value, other.Value);
    }

    #endregion

    public override bool Equals(object obj)
    {
        if (obj is XmlEnumWrapper<TEnum>)
            return Equals((XmlEnumWrapper<TEnum>)obj);
        return Value.Equals(obj);
    }

    public override int GetHashCode()
    {
        return Value.GetHashCode();
    }

    public override string ToString()
    {
        return Value.ToString();
    }
}
公共类Foo
{
[XmlIgnore]
public MyEnum MyEnum{get;set;}
[XmlElement(“条”)]
[可浏览(false)、可编辑(EditorBrowsableState.Never)、可调试(DebuggerBrowsableState.Never)]
公共XmlEnumWrapper myEnumXml{get{return myEnum;}set{myEnum=value;}}
}
public struct XmlEnumWrapper:IEquatable其中TEnum:struct,IConvertible,IComparable,IFormattable
{
TEnum值;
公共XmlEnumWrapper(TEnum值)
{
这个值=值;
}
公共静态隐式运算符TEnum(XmlEnumWrapper)
{
返回wrapper.Value;
}
公共静态隐式运算符XmlEnumWrapper(TEnum anEnum)
{
返回新的XmlEnumWrapper(anEnum);
}
公共静态布尔运算符==(XmlEnumWrapper第一,XmlEnumWrapper第二)
{
返回第一,等于(第二);
}
公共静态布尔运算符!=(XmlEnumWrapper第一,XmlEnumWrapper第二)
{
返回!第一。等于(第二);
}
[XmlIgnore]
公共十位数值{get{return Value;}私有集{this.Value=Value;}}
[XmlText]
公共字符串值字符串
{
得到
{
返回值.ToString();
}
设置
{
//如果需要解析XmlEnumAttribute属性,请参见此处
// http://stackoverflow.com/questions/3047125/retrieve-enum-value-based-on-xmlenumattribute-name-value
value=value.Trim();
Value=(TEnum)Enum.Parse(typeof(TEnum),Value,false);
}
}
#区域可容纳成员
公共布尔等于(其他)
{
返回EqualityComparer.Default.Equals(Value,other.Value);
}
#端区
公共覆盖布尔等于(对象对象对象)
{
if(obj是XmlEnumWrapper)
返回等于((XmlEnumWrapper)obj);
返回值。等于(obj);
}
公共覆盖int GetHashCode()
{
返回值。GetHashCode();
}
公共重写字符串ToString()
{
返回值.ToString();
}
}

这还允许您添加同义词处理或处理未知值,而无需在必要时引发异常。

您可以在反序列化时使用自定义反序列化程序“清理”数据。或者是效率极低的string.replace在反序列化之前剥离XML中的所有空格(我可能会因为提出这个替代方案而被社区绞死)。你能展示你用来反序列化的代码吗?这可能与添加.Trim()代码一样简单。请获取更多信息抱歉,我手头没有反序列化代码。不过,这只是一个标准操作,XML响应被传递到反序列化()方法中。忽略效率低下的问题,剥离所有空间是行不通的,因为大多数XML值都需要它们的空间(即大量文本)。明天早上我会让你知道我的进展!不幸的是,性能是一个问题。此外,我不能修剪每个值,因为大多数人都需要发送这些值的空格(即大量文本)。我的目标是能够只修剪不需要空格的值,以避免任何错误被抛出行中。这不会修剪每个值,它只修剪名为
Bar
的元素的值。您可以使用任何查询,任何您喜欢的自定义逻辑。和以往一样,在性能方面,尝试各种选择和措施。哦,是的,我很抱歉,一定是误解了这一点。我可能会接受这个想法。这取决于如何实现,以便将需要检查的所有值连接起来。明天早上我会让你知道我的进展!
var doc = XDocument.Parse(xml);

foreach (var bar in doc.Descendants("Bar"))
{
    bar.Value = bar.Value.Trim();
}

using (var reader = doc.CreateReader())
{
    var obj = serializer.Deserialize(reader);
}
public class Foo
{
    [XmlIgnore]
    public MyEnum myEnum { get; set; }

    [XmlElement("Bar")]
    [EditorBrowsable(EditorBrowsableState.Never)]
    public string _myEnum
    {
        get { return myEnum.ToString(); }
        set { myEnum = (MyEnum)Enum.Parse(typeof(MyEnum), value.Trim()); }
    }
}
public class Foo
{
    [XmlIgnore]
    public MyEnum myEnum { get; set; }

    [XmlElement("Bar")]
    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DebuggerBrowsable(DebuggerBrowsableState.Never)]
    public XmlEnumWrapper<MyEnum> myEnumXml { get { return myEnum; } set { myEnum = value; } }
}

public struct XmlEnumWrapper<TEnum> : IEquatable<XmlEnumWrapper<TEnum>> where TEnum : struct, IConvertible, IComparable, IFormattable
{
    TEnum value;

    public XmlEnumWrapper(TEnum value)
    {
        this.value = value;
    }

    public static implicit operator TEnum(XmlEnumWrapper<TEnum> wrapper)
    {
        return wrapper.Value;
    }

    public static implicit operator XmlEnumWrapper<TEnum>(TEnum anEnum)
    {
        return new XmlEnumWrapper<TEnum>(anEnum);
    }

    public static bool operator ==(XmlEnumWrapper<TEnum> first, XmlEnumWrapper<TEnum> second)
    {
        return first.Equals(second);
    }

    public static bool operator !=(XmlEnumWrapper<TEnum> first, XmlEnumWrapper<TEnum> second)
    {
        return !first.Equals(second);
    }

    [XmlIgnore]
    public TEnum Value { get { return value; } private set { this.value = value; } }

    [XmlText]
    public string ValueString
    {
        get
        {
            return Value.ToString();
        }
        set
        {
            // See here if one needs to parse XmlEnumAttribute attributes
            // http://stackoverflow.com/questions/3047125/retrieve-enum-value-based-on-xmlenumattribute-name-value
            value = value.Trim();
            Value = (TEnum)Enum.Parse(typeof(TEnum), value, false);
        }
    }

    #region IEquatable<XmlEnumWrapper<TEnum>> Members

    public bool Equals(XmlEnumWrapper<TEnum> other)
    {
        return EqualityComparer<TEnum>.Default.Equals(Value, other.Value);
    }

    #endregion

    public override bool Equals(object obj)
    {
        if (obj is XmlEnumWrapper<TEnum>)
            return Equals((XmlEnumWrapper<TEnum>)obj);
        return Value.Equals(obj);
    }

    public override int GetHashCode()
    {
        return Value.GetHashCode();
    }

    public override string ToString()
    {
        return Value.ToString();
    }
}