C#:从通用类型名称获取XML元素名称的最佳方法 [英] C#: Best way to have XML element name from generic type name

查看:235
本文介绍了C#:从通用类型名称获取XML元素名称的最佳方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I want to create a xml for a generic class. One of the properties has the generic type. For this property I don't want to use the property name as its XML element name, but the name of the generic type.

该类如下:

[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; }
}

序列化类型为StoreItem<SewageArea>的商店商品时,XML应包含以下内容:

When serializing a store item of kind StoreItem<SewageArea> the XML should contain something like:

<Entity Status="Deleted">
    <SewageArea ...>
       ...
    </SewageArea>
<Entity>

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

The requirement is, that the SewageArea in the above example should be serialized in the "normal" way. Another important thing is that if its possible the code should be prepared to automatically serializes new added properties at the StoreItemclass.

推荐答案

您希望按照

You'd like to do something along the lines of Rename class when serializing to XML but you cannot because attribute arguments cannot contain generic type parameters, i.e. [XmlElement(typeof(TEntity))]. And the obvious alternative of implementing IXmlSerializable is inconvenient because you lose automatic serialization of properties subsequently added to StoreItem<TEntity>.

相反,您可以做的是利用

Instead, what you can do is to make use of an [XmlAnyElement] surrogate property to do a nested serialization of your TEntity, as follows:

[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));
        }
    }
}

使用扩展方法:

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;
    }
}

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

Note that the [XmlAnyElement] property will be called for all unknown elements, so if your XML for some reason has unexpected elements, you may get an exception thrown from XObjectExtensions.Deserialize<TEntity>(value)) because the root element name is wrong. You may want to catch and ignore exceptions from this method if that is a possibility.

然后,为示例TEntity

public class SewageArea
{
    public double Area { get; set; }
}

XML输出为:

<Entity Status="State1">
  <SewageArea>
    <Area>10101</Area>
  </SewageArea>
</Entity>

示例小提琴.

这篇关于C#:从通用类型名称获取XML元素名称的最佳方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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