C#:从泛型类型名称获取XML元素名称的最佳方法

sch*_*her 1 c# xml generics xml-serialization

我想为泛型类创建一个xml.其中一个属性具有泛型类型.对于此属性,我不希望将属性名称用作其XML元素名称,而是使用泛型类型的名称.

这个类看起来像这样:

[XmlRoot("Entity")]
public class StoreItem<TEntity>
    where TEntity : class, new()
{
    /// <summary>
    /// Gets and sets the status of the entity when storing.
    /// </summary>
    [XmlAttribute]
    public System.Data.Services.Client.EntityStates Status { get; set; }

    /// <summary>
    /// Gets and sets the entity to be stored.
    /// </summary>
    public TEntity Entity { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

在序列化某种商店项目时StoreItem<SewageArea>,XML应包含以下内容:

<Entity Status="Deleted">
    <SewageArea ...>
       ...
    </SewageArea>
<Entity>
Run Code Online (Sandbox Code Playgroud)

要求是,SewageArea上面的例子应该以"正常"方式序列化.另一个重要的事情是,如果可能的话,代码应该准备好在类中自动序列化新添加的属性StoreItem.

dbc*_*dbc 6

在序列化为XML时,您希望沿着Rename类的行执行某些操作,但是您不能因为属性参数不能包含泛型类型参数,即[XmlElement(typeof(TEntity))].而实施的明显替代方案IXmlSerializable是不方便的,因为您丢失了随后添加到的属性的自动序列化StoreItem<TEntity>.

相反,你可以做的是让使用的[XmlAnyElement]替代性质做了嵌套的系列化你的TEntity,如下:

[XmlRoot("Entity")]
public class StoreItem<TEntity>
    where TEntity : class, new()
{
    /// <summary>
    /// Gets and sets the status of the entity when storing.
    /// </summary>
    [XmlAttribute]
    public System.Data.Services.Client.EntityStates Status { get; set; }

    /// <summary>
    /// Gets and sets the entity to be stored.
    /// </summary>
    [XmlIgnore]
    public TEntity Entity { get; set; }

    [XmlAnyElement]
    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DebuggerBrowsable(DebuggerBrowsableState.Never)]
    public XElement XmlEntity
    {
        get
        {
            return (Entity == null ? null : XObjectExtensions.SerializeToXElement(Entity, null, true));
        }
        set
        {
            Entity = (value == null ? null : XObjectExtensions.Deserialize<TEntity>(value));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

使用扩展方法:

public static class XObjectExtensions
{
    public static T Deserialize<T>(this XContainer element)
    {
        return element.Deserialize<T>(null);
    }

    public static T Deserialize<T>(this XContainer element, XmlSerializer serializer)
    {
        using (var reader = element.CreateReader())
        {
            serializer = serializer ?? new XmlSerializer(typeof(T));
            object result = serializer.Deserialize(reader);
            if (result is T)
                return (T)result;
        }
        return default(T);
    }

    public static XElement SerializeToXElement<T>(this T obj)
    {
        return obj.SerializeToXElement(null, true);
    }

    public static XElement SerializeToXElement<T>(this T obj, XmlSerializer serializer, bool omitStandardNamespaces)
    {
        var doc = new XDocument();
        using (var writer = doc.CreateWriter())
        {
            XmlSerializerNamespaces ns = null;
            if (omitStandardNamespaces)
                (ns = new XmlSerializerNamespaces()).Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines.
            serializer = serializer ?? new XmlSerializer(obj.GetType());
            serializer.Serialize(writer, obj, ns);
        }
        var element = doc.Root;
        if (element != null)
            element.Remove();
        return element;
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,[XmlAnyElement]将为所有未知元素调用该属性,因此如果您的XML由于某种原因具有意外元素,则可能会XObjectExtensions.Deserialize<TEntity>(value))因为根元素名称错误而引发异常.如果可能,您可能希望捕获并忽略此方法的异常.

然后,为样本TEntity

public class SewageArea
{
    public double Area { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

XML输出是:

<Entity Status="State1">
  <SewageArea>
    <Area>10101</Area>
  </SewageArea>
</Entity>
Run Code Online (Sandbox Code Playgroud)

样品小提琴.