【问题标题】:C# XmlSerializer Serialize the same class with different namespacesC# XmlSerializer 用不同的命名空间序列化同一个类
【发布时间】:2021-07-04 09:07:43
【问题描述】:

假设我有一堂课:

using System.Xml;
using System.Xml.Serialization;

class Foo {
    [XmlElement(ElementName="Bar")]
    public string Bar {get; set;}
}

现在我想序列化它。但。我想指定不同的命名空间, 有一次我希望我的 XML 看起来像这样:

<Foo xmlns:v1="http://site1">
    <v1:Bar />
</Foo>

另一方面,像这样:

<Foo xmlns:v2="http://site2">
    <v2:Bar />
</Foo>

我知道我需要在 XmlElement 属性中指定命名空间,但这正是我想要避免的。 当然,我可以制作 2 个不同的类,除了字段属性之外它们是相同的,但这在某种程度上感觉是错误的。 有什么办法可以强制 XmlSerializer 使用我在运行时选择的命名空间?

【问题讨论】:

    标签: c# xml xml-serialization xmlserializer


    【解决方案1】:

    是的; XmlAttributeOverrides:

        static void Main()
        {
            var obj = new Foo { Bar = "abc" };
            GetSerializer("http://site1").Serialize(Console.Out, obj);
            Console.WriteLine();
            GetSerializer("http://site2").Serialize(Console.Out, obj);
        }
        static XmlSerializer GetSerializer(string barNamespace)
        {
            var ao = new XmlAttributeOverrides();
            var a = new XmlAttributes();
            a.XmlElements.Add(new XmlElementAttribute { Namespace = barNamespace });
            ao.Add(typeof(Foo), nameof(Foo.Bar), a);
            return new XmlSerializer(typeof(Foo), ao);
        }
    

    但是!!!

    当你这样做时,它每次都会在内存中生成一个额外的程序集;您必须缓存并重复使用序列化程序实例 - 通常通过并发字典或类似方式。例如:

    private static readonly ConcurrentDictionary<string, XmlSerializer>
        s_serializersByNamespace = new();
    static XmlSerializer GetSerializer(string barNamespace)
    {
        if (!s_serializersByNamespace.TryGetValue(barNamespace, out var serializer))
        {
            lock (s_serializersByNamespace)
            {
                // double-checked, avoid dups
                if (!s_serializersByNamespace.TryGetValue(barNamespace, out serializer))
                {
                    var ao = new XmlAttributeOverrides();
                    var a = new XmlAttributes();
                    a.XmlElements.Add(new XmlElementAttribute { Namespace = barNamespace });
                    ao.Add(typeof(Foo), nameof(Foo.Bar), a);
                    serializer = new XmlSerializer(typeof(Foo), ao);
                    s_serializersByNamespace[barNamespace] = serializer;
                }
            }
        }
        return serializer;
    }
    

    注意:如果你也想要特定的xmlns 控件,那就是XmlSerializerNamespaces

            var obj = new Foo { Bar = "abc" };
            var ns = new XmlSerializerNamespaces();
            ns.Add("v1", "http://site1");
            GetSerializer("http://site1").Serialize(Console.Out, obj, ns);
    
            Console.WriteLine();
    
            ns = new XmlSerializerNamespaces();
            ns.Add("v2", "http://site2");
            GetSerializer("http://site2").Serialize(Console.Out, obj, ns);
    

    【讨论】:

    • 我想我必须为我的每个类可序列化属性一个一个地添加一个覆盖?
    • @cicatrix 是的,虽然我相信相同的属性 instances 如果它们相似的话可以被重用;把它想象成常规属性:你需要单独应用它们每个成员
    猜你喜欢
    • 2015-06-30
    • 1970-01-01
    • 2021-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-08
    • 2011-07-12
    • 2011-03-15
    相关资源
    最近更新 更多