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(只需要一个自定义的根节点名称!)

相关文章

本程序的编译和运行环境如下(如果有运行方面的问题欢迎在评...
水了一学期的院选修,万万没想到期末考试还有比较硬核的编程...
补充一下,先前文章末尾给出的下载链接的完整代码含有部分C&...
思路如标题所说采用模N取余法,难点是这个除法过程如何实现。...
本篇博客有更新!!!更新后效果图如下: 文章末尾的完整代码...
刚开始学习模块化程序设计时,估计大家都被形参和实参搞迷糊...