C# XmlSerializer 使用不同的命名空间序列化相同的 class
C# XmlSerializer Serialize the same class with different namespaces
假设我有一个 class:
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 个不同的 classes,它们除了字段属性外都是相同的,但这不知何故感觉不对。
有什么方法可以强制 XmlSerializer 使用我在运行时选择的名称空间?
是; 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);
假设我有一个 class:
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 个不同的 classes,它们除了字段属性外都是相同的,但这不知何故感觉不对。 有什么方法可以强制 XmlSerializer 使用我在运行时选择的名称空间?
是; 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);