微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

C#Xml序列化,集合和根元素

我的应用程序串行化流中的对象.
以下是我需要的样本:
<links>
  <link href="/users" rel="users" />
  <link href="/features" rel="features" />
</links>

在这种情况下,对象是’links’对象的集合.

———–第一版

起初我使用DataContractSerializer,但是不能将成员序列化为属性(source)

这是对象:

[DataContract(Name="link")]
public class LinkV1
{
    [DataMember(Name="href")]
    public string Url { get; set; }

    [DataMember(Name="rel")]
    public string Relationship { get; set; }
}

结果如下:

<ArrayOflink xmlns:i="...." xmlns="...">
  <link>
    <href>/users</href>
    <rel>users</rel>
  </link>
  <link>
    <href>/features</href>
    <rel>features</rel>
  </link>
</ArrayOflink>

———–第二版

好的,不安静我想要的,所以我尝试了经典的XmlSerializer,但是…哦,哦,你不能指定根元素的名称&的集合元素如果根元素是一个集合…

这是代码

[XmlRoot("link")]
public class LinkV2
{
    [XmlAttribute("href")]
    public string Url { get; set; }

    [XmlAttribute("rel")]
    public string Relationship { get; set; }
}

结果如下:

<ArrayOfLinkV2>
  <LinkV2 href="/users" rel="users" />
  <LinkV2 href="/features" rel="features" />
  <LinkV2 href="/features/user/{keyUser}" rel="featuresByUser" />
</ArrayOfLinkV2>

———–第三版

使用XmlSerializer一个根元素:

[XmlRoot("trick")]
public class TotallyUselessClass
{
    [XmlArray("links"),XmlArrayItem("link")]
    public List<LinkV2> Links { get; set; }
}

其结果:

<trick>
  <links>
    <link href="/users" rel="users" />
    <link href="/features" rel="features" />
    <link href="/features/user/{keyUser}" rel="featuresByUser" />
  </links>
</trick>

尼斯,但我不想要那个根节点!
我希望我的收藏是根节点.

以下是约束:

>序列化代码是通用的,它可以与任何可序列化的方式一起使用
>反操作(反序列化)也必须工作
>我不想正则表达式(我在输出流中直接序列化)

我现在的解决方案是什么

编码我自己的XmlSerializer
> Trick XmlSerializer当它与一个集合工作(我试过,找到一个XmlRootElement和plurialize它来生成自己的XmlRootAttribute,但是当反序列化项目名称仍然保持类名时会导致问题)

任何想法 ?

在这个问题上真正困扰我的是,我想要的似乎真的很简单

解决方法

好的,这是我的最终解决方案(希望它有助于某人),可以序列化一个纯数组,List<>,HashSet&

要实现这一点,我们需要告诉serializer什么根节点使用,这是一个棘手的…

1)在可序列化的对象上使用’XmlType’

[XmlType("link")]
public class LinkFinalVersion
{
    [XmlAttribute("href")]
    public string Url { get; set; }

    [XmlAttribute("rel")]
    public string Relationship { get; set; }
}

2)编写一个“智能根检测器收集”方法,这将返回一个XmlRootAttribute

private XmlRootAttribute XmlRootForCollection(Type type)
{
    XmlRootAttribute result = null;

    Type typeInner = null;
    if(type.IsGenericType)
    {
        var typeGeneric = type.GetGenericArguments()[0];
        var typeCollection = typeof (ICollection<>).MakeGenericType(typeGeneric);
        if(typeCollection.IsAssignableFrom(type))
            typeInner = typeGeneric;
    }
    else if(typeof (ICollection).IsAssignableFrom(type)
        && type.HasElementType)
    {
        typeInner = type.GetElementType();
    }

    // yeepeeh ! if we are working with a collection
    if(typeInner != null)
    {
        var attributes = typeInner.GetCustomAttributes(typeof (XmlTypeAttribute),true);
        if((attributes != null)
            && (attributes.Length > 0))
        {
            var typeName = (attributes[0] as XmlTypeAttribute).TypeName + 's';
            result = new XmlRootAttribute(typeName);
        }
    }
    return result;
}

3)将该XmlRootAttribute推送到序列化程序中

// hack : get the XmlRootAttribute if the item is a collection
var root = XmlRootForCollection(type);
// create the serializer
var serializer = new XmlSerializer(type,root);

我告诉你这很棘手;)

为了改善这一点,您可以:

A)创建一个XmlTypeInCollectionAttribute来指定自定义名称(如果基本的复合不符合您的需要)

[XmlType("link")]
[XmlTypeInCollection("links")]
public class LinkFinalVersion
{
}

B)如果可能,缓存您的XmlSerializer(例如在静态字典中).

在我的测试中,建立一个没有XmlRootAttributes的XmlSerializer需要3ms.如果指定一个XmlRootAttribute,它大约需要80ms(只需要一个自定义的根节点名称!)

原文地址:https://www.jb51.cc/c/113405.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐