Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 序列化类的一部分时,有没有保留XML属性的方法?_C#_Wpf_Serialization_Xml Serialization_Xml Attribute - Fatal编程技术网

C# 序列化类的一部分时,有没有保留XML属性的方法?

C# 序列化类的一部分时,有没有保留XML属性的方法?,c#,wpf,serialization,xml-serialization,xml-attribute,C#,Wpf,Serialization,Xml Serialization,Xml Attribute,我正试图序列化一个类的一部分。我已将XML属性添加到类成员中,以便正确命名生成的XML标记以匹配规范,而不管我的属性命名为什么。当序列化主类时,这可以很好地工作。但是,如果我只想序列化类的一部分,我将丢失XML属性,名称将恢复为默认值。当序列化一个类的一部分时,有没有办法保留XML属性 [XmlRoot ("someConfiguration")] public class SomeConfiguration { [XmlArray("bugs")] [XmlArrayItem(

我正试图序列化一个类的一部分。我已将XML属性添加到类成员中,以便正确命名生成的XML标记以匹配规范,而不管我的属性命名为什么。当序列化主类时,这可以很好地工作。但是,如果我只想序列化类的一部分,我将丢失XML属性,名称将恢复为默认值。当序列化一个类的一部分时,有没有办法保留XML属性

[XmlRoot ("someConfiguration")]
public class SomeConfiguration
{
    [XmlArray("bugs")]
    [XmlArrayItem("bug")]
    public List<string> Bugs { get; set; }
}
[XmlRoot(“someConfiguration”)]
公共类配置
{
[XmlArray(“bug”)]
[XmlArrayItem(“bug”)]
公共列表错误{get;set;}
}
当我序列化整个类时,我得到了以下结果(这正是我所期望的):


Bug1
Bug2
Bug3
如果我试图序列化类的“bug”部分,我会得到这样的结果(注意,更改标记名的XML属性都会被忽略):


Bug1
Bug2
Bug3
我需要得到这个:

  <bugs>
    <bug>Bug1</bug>
    <bug>Bug2</bug>
    <bug>Bug3</bug>
  </bugs>

Bug1
Bug2
Bug3
如何让分部类用上述标记序列化

或者更好的是,在序列化一个简单的
列表时,有没有一种方法可以指定标记名。因此,您可以使用
指定用于列表的标记,而不是它,并指定用于数组项的标记,而不是

序列化简单列表时是否有指定标记名的方法

一般来说,根据具体情况,可能会实现这一点。请参阅MSDN。这里的示例涉及重写特定字段的序列化,但也可以使用相同的技术重写整个类型名

但这对我来说似乎是一个很大的麻烦。相反,为什么不显式地处理序列化:

private static string SerializeByLinqAndToString<T>(
    List<T> data, string rootName, string elementName)
{
    XDocument document = new XDocument(
        new XElement(rootName, data.Select(s => new XElement(elementName, s))));

    return SaveXmlToString(document);
}

private static string SaveXmlToString(XDocument document)
{
    StringBuilder sb = new StringBuilder();

    using (XmlWriter xmlWriter = XmlWriter.Create(sb,
        new XmlWriterSettings { Indent = true, OmitXmlDeclaration = true }))
    {
        document.Save(xmlWriter);
    }

    return sb.ToString();
}
以上仅适用于字符串列表或类型列表,其中元素内容可以是对类型实例调用
ToString()
的结果

在处理复杂类型时,在.NET中使用全面的序列化功能可能是值得的,但是如果您所拥有的只是一个简单的字符串列表,那么LINQ to XML功能非常方便

如果确实有更复杂的类型,则可以将每个列表元素转换为DOM的
XElement
,并序列化:

private static string SerializeByLinq<T>(
    List<T> data, string rootName, string elementName = null)
{
    XDocument document = new XDocument(
        new XElement(rootName, data.Select(t =>
            ElementFromText(SerializeObject(t), elementName)
        )));

    return SaveXmlToString(document);
}

private static XElement ElementFromText(string xml, string name = null)
{
    StringReader reader = new StringReader(xml);
    XElement result = XElement.Load(reader);

    if (!string.IsNullOrEmpty(name))
    {
        result.Name = name;
    }

    return result;
}

private static string SerializeObject<T>(T o)
{
    XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
    StringWriter textWriter = new StringWriter();

    using (XmlWriter writer = XmlWriter.Create(textWriter,
        new XmlWriterSettings { Indent = true, OmitXmlDeclaration = true }))
    {
        xmlSerializer.Serialize(writer, o,
            new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty}));
    }

    return textWriter.ToString();
}
private静态字符串序列化bylinq(
列表数据,字符串rootName,字符串elementName=null)
{
XDocument document=新XDocument(
新建XElement(rootName,data.Select(t=>
ElementFromText(序列化对象(t),elementName)
)));
返回SaveXmlToString(文档);
}
私有静态XElement元素fromText(字符串xml,字符串名称=null)
{
StringReader=新的StringReader(xml);
XElement结果=XElement.Load(读卡器);
如果(!string.IsNullOrEmpty(名称))
{
result.Name=Name;
}
返回结果;
}
私有静态字符串序列化对象(TO)
{
XmlSerializer XmlSerializer=新的XmlSerializer(typeof(T));
StringWriter textWriter=新StringWriter();
使用(XmlWriter=XmlWriter.Create)(textWriter,
新的XmlWriterSettings(缩进=true,省略XmlDeclaration=true})
{
serializer.Serialize(writer,o,
新的XmlSerializerNamespaces(新[]{XmlQualifiedName.Empty});
}
返回textWriter.ToString();
}

在第二个示例中,您可以省略子元素的元素名称,它将只使用类型设置为已使用的任何内容(例如,类型名称,或
[XmlRoot]
设置为的任何内容)。

找到了一种“变通”方法。。不要将XMLArray和XMLArrayList属性放在列表上方:

[XmlRoot(“someConfiguration”)]
公共类配置
{
[XmlArray(“bug”)]
[XmlArrayItem(“bug”)]
公共列表错误{get;set;}
}
在列表上放置一个XmlElement属性,该属性将指定每个元素要使用的标记,而不包含包装列表的标记。你的class标签实际上会帮你做到这一点

[XmlRoot ("bugs")]
public class SomeConfiguration
{
    [XmlElement("bug")]
    public List<string> Bugs { get; set; }
}
[XmlRoot(“bug”)]
公共类配置
{
[XmlElement(“bug”)]
公共列表错误{get;set;}
}
当您序列化上述内容时,您将得到:

  <bugs>
    <bug>Bug1</bug>
    <bug>Bug2</bug>
    <bug>Bug3</bug>
  </bugs>

Bug1
Bug2
Bug3

只要将其抛出,您就可以将列表包装到自定义类中:

[XmlRoot("config")]
public class SomeConfiguration
{
    [XmlElement("bugs")]
    public BugList Bugs { get; set; }
    [XmlElement("trees")]
    public TreeList Trees { get; set; }
}

[XmlRoot("bugs")]
public class BugList 
{
    [XmlElement("bug")]
    public List<string> Items = new List<string>();
}

[XmlRoot("trees")]
public class TreeList
{
    [XmlElement("tree")]
    public List<string> Items = new List<string>();
}   
[XmlRoot(“配置”)]
公共类配置
{
[XmlElement(“bug”)]
公共错误列表错误{get;set;}
[XmlElement(“树”)]
公共树列表树{get;set;}
}
[XmlRoot(“bug”)]
公共类错误列表
{
[XmlElement(“bug”)]
公共列表项=新列表();
}
[XmlRoot(“树”)]
公共级树人
{
[XmlElement(“树”)]
公共列表项=新列表();
}   
现在,这将允许您序列化各个列表,并且它们将按照您的预期扎根

void Main()
{
    var config = new SomeConfiguration
    {
        Bugs = new BugList { Items = { "Bug1", "Bug2" } },
        Trees = new TreeList { Items = { "Tree1", "Tree2" } }
    };

    // Your config will work as normal.
    Debug.WriteLine(ToXml(config)); // <config> <bugs>.. <trees>..</config>

    // Your collections are now root-ed properly.
    Debug.WriteLine(ToXml(config.Bugs)); // <bugs><bug>Bug1</bug><bug>Bug2</bug></bugs>
    Debug.WriteLine(ToXml(config.Trees)); // <trees><tree>Tree1</tree><tree>Tree2</tree></trees>
}

public string ToXml<T>(T obj)
{
    var ser = new XmlSerializer(typeof(T));
    var emptyNs = new XmlSerializerNamespaces();
    emptyNs.Add("","");
    using (var stream = new MemoryStream())
    {
        ser.Serialize(stream, obj, emptyNs);
        return Encoding.ASCII.GetString(stream.ToArray());
    }
}
void Main()
{
var config=new SomeConfiguration
{
Bugs=新错误列表{Items={“Bug1”,“Bug2”},
树=新树列表{Items={“Tree1”,“Tree2”}
};
//您的配置将正常工作。
Debug.WriteLine(ToXml(config));/。。
//您的集合现在已正确根目录。
Debug.WriteLine(ToXml(config.Bugs));//Bug1Bug2
Debug.WriteLine(ToXml(config.Trees));//Tree1Tree2
}
公共字符串ToXml(T obj)
{
var ser=新的XmlSerializer(typeof(T));
var emptyNs=新的XmlSerializerNamespaces();
emptyNs.Add(“,”);
使用(var stream=new MemoryStream())
{
序列化(流、对象、空同步);
返回Encoding.ASCII.GetString(stream.ToArray());
}
}

我尝试使用“字符串”以外的类型,它显示的是“bug”对象的“ToString()”表示,而不是XML表示。@Curtis:是的。您的问题是关于序列化
string
值列表,而不是其他对象。其他
[XmlRoot ("bugs")]
public class SomeConfiguration
{
    [XmlElement("bug")]
    public List<string> Bugs { get; set; }
}
  <bugs>
    <bug>Bug1</bug>
    <bug>Bug2</bug>
    <bug>Bug3</bug>
  </bugs>
[XmlRoot("config")]
public class SomeConfiguration
{
    [XmlElement("bugs")]
    public BugList Bugs { get; set; }
    [XmlElement("trees")]
    public TreeList Trees { get; set; }
}

[XmlRoot("bugs")]
public class BugList 
{
    [XmlElement("bug")]
    public List<string> Items = new List<string>();
}

[XmlRoot("trees")]
public class TreeList
{
    [XmlElement("tree")]
    public List<string> Items = new List<string>();
}   
void Main()
{
    var config = new SomeConfiguration
    {
        Bugs = new BugList { Items = { "Bug1", "Bug2" } },
        Trees = new TreeList { Items = { "Tree1", "Tree2" } }
    };

    // Your config will work as normal.
    Debug.WriteLine(ToXml(config)); // <config> <bugs>.. <trees>..</config>

    // Your collections are now root-ed properly.
    Debug.WriteLine(ToXml(config.Bugs)); // <bugs><bug>Bug1</bug><bug>Bug2</bug></bugs>
    Debug.WriteLine(ToXml(config.Trees)); // <trees><tree>Tree1</tree><tree>Tree2</tree></trees>
}

public string ToXml<T>(T obj)
{
    var ser = new XmlSerializer(typeof(T));
    var emptyNs = new XmlSerializerNamespaces();
    emptyNs.Add("","");
    using (var stream = new MemoryStream())
    {
        ser.Serialize(stream, obj, emptyNs);
        return Encoding.ASCII.GetString(stream.ToArray());
    }
}