[英]C# XMLSerializer is deserializing the wrong type into a List
The program below is a contrived example of a problem I found when deserializing XML in C#. 下面的程序是我在C#中反序列化XML时发现的一个问题的例子。 I have two separate assemblies which declare a type with the same name, 'Country' in the example below.
我有两个单独的程序集,它们声明一个具有相同名称的类型,在下面的示例中为“Country”。 The types are differentiated by XML namespace.
这些类型由XML命名空间区分。 When I deserialize a configuration file containing a single 'Country' element then the correct 'Country' type is resolved.
当我反序列化包含单个“Country”元素的配置文件时,将解析正确的“Country”类型。 However if I deserialize a 'List' of 'Country' elements then the wrong 'Country' type is deserialized.
但是,如果我反序列化“Country”元素的“List”,则反序列化错误的“Country”类型。
class Program
{
static void Main(string[] args)
{
XDocument gbConfig = XDocument.Parse(@"<TradingBlocConfiguration>
<GreatBritain>
<Country/>
<Countries>
<Country/>
<Country/>
</Countries>
</GreatBritain> </TradingBlocConfiguration>");
XDocument euConfig = XDocument.Parse(@"<TradingBlocConfiguration>
<EuropeanUnion>
<Country/>
<Countries>
<Country/>
<Country/>
</Countries>
</EuropeanUnion> </TradingBlocConfiguration>");
var greatBritainConfiguration = BuildConfig<TradingBlocConfiguration>(gbConfig);
// A single 'Country' is always deserialized correctly..
Console.WriteLine("Great Britain Country Type " + greatBritainConfiguration.TradingBlocConfig.MemberCountry.GetType());
// A List of 'Country' is deserialized to the wrong type, depending on what '[XmlElement]' tag is listed first.
Console.WriteLine("Great Britain Countries Type " + greatBritainConfiguration.TradingBlocConfig.MemberCountries[0].GetType());
var euConfiguration = BuildConfig<TradingBlocConfiguration>(euConfig);
Console.WriteLine("EU Country Type " + euConfiguration.TradingBlocConfig.MemberCountry.GetType());
Console.WriteLine("EU Countries Type " + euConfiguration.TradingBlocConfig.MemberCountries[0].GetType());
Console.ReadLine();
}
private static T BuildConfig<T>(XDocument doc) where T : class
{
var stream = new MemoryStream();
doc.Save(stream);
T result;
using (var reader = new StreamReader(stream))
{
stream.Position = 0;
var xs = new XmlSerializer(typeof(T));
result = (T)xs.Deserialize(reader);
}
return result;
}
}
[XmlRoot("TradingBlocConfiguration")]
public sealed class TradingBlocConfiguration
{
[XmlElement("GreatBritain", typeof(GB.GreatBritain))]
[XmlElement("EuropeanUnion", typeof(EU.EuropeanUnion))]
public TradingBloc TradingBlocConfig { get; set; }
}
[XmlRoot]
[XmlInclude(typeof(GB.GreatBritain))]
[XmlInclude(typeof(EU.EuropeanUnion))]
public class BaseCountry { }
public abstract class TradingBloc
{
[XmlIgnore]
public abstract List<BaseCountry> MemberCountries { get; set; }
[XmlIgnore]
public abstract BaseCountry MemberCountry { get; set; }
}
namespace GB
{
[XmlRoot("GreatBritain")]
public class GreatBritain : TradingBloc
{
[XmlElement("Country", typeof(Country))]
public override BaseCountry MemberCountry { get; set; }
[XmlArray("Countries")]
[XmlArrayItem("Country", typeof(Country))]
public override List<BaseCountry> MemberCountries { get; set; }
[XmlRoot(Namespace = "GB")]
public class Country : BaseCountry { }
}
}
namespace EU
{
[XmlRoot("EuropeanUnion")]
public class EuropeanUnion : TradingBloc
{
[XmlElement("Country", typeof(Country))]
public override BaseCountry MemberCountry { get; set; }
[XmlArray("Countries")]
[XmlArrayItem("Country", typeof(Country))]
public override List<BaseCountry> MemberCountries { get; set; }
[XmlRoot(Namespace = "EU")]
public class Country : BaseCountry { }
}
}
If you run the example above the output is: 如果您运行上面的示例,则输出为:
Great Britain Country Type XmlSerializationTests.GB.GreatBritain+Country
Great Britain Countries Type XmlSerializationTests.EU.EuropeanUnion+Country
EU Country Type XmlSerializationTests.EU.EuropeanUnion+Country
EU Countries Type XmlSerializationTests.EU.EuropeanUnion+Country
The 'Great Britain Countries Type' is incorrect. “英国国家类型”不正确。 If you change the order of [XmlElement] attributes in the TradingBlocConfiguration class like:
如果您更改TradingBlocConfiguration类中[XmlElement]属性的顺序,如:
[XmlRoot("TradingBlocConfiguration")]
public sealed class TradingBlocConfiguration
{
[XmlElement("EuropeanUnion", typeof(EU.EuropeanUnion))]
[XmlElement("GreatBritain", typeof(GB.GreatBritain))]
public TradingBloc TradingBlocConfig { get; set; }
}
Then the results changes to: 然后结果变为:
Great Britain Country Type XmlSerializationTests.GB.GreatBritain+Country
Great Britain Countries Type XmlSerializationTests.GB.GreatBritain+Country
EU Country Type XmlSerializationTests.EU.EuropeanUnion+Country
EU Countries Type XmlSerializationTests.GB.GreatBritain+Country
In this case Britain looks good but the EU is wrong :). 在这种情况下,英国看起来不错,但欧盟错了:)。 Can anyone explain why the List is deserialized to the wrong type?
任何人都可以解释为什么List被反序列化为错误的类型?
Solution was to add xmlns tags. 解决方案是添加xmlns标记。 The updated code below works correctly:
以下更新的代码正常工作:
class Program
{
static void Main(string[] args)
{
XDocument gbConfig = XDocument.Parse(@"<TradingBlocConfiguration>
<GreatBritain xmlns=""GB"">
<Country/>
<Countries>
<Country/>
<Country/>
</Countries>
</GreatBritain> </TradingBlocConfiguration>");
XDocument euConfig = XDocument.Parse(@"<TradingBlocConfiguration>
<EuropeanUnion xmlns=""EU"">
<Country/>
<Countries>
<Country/>
<Country/>
</Countries>
</EuropeanUnion> </TradingBlocConfiguration>");
var greatBritainConfiguration = BuildConfig<TradingBlocConfiguration>(gbConfig);
// A single 'Country' is always deserialized correctly..
Console.WriteLine("Great Britain Country Type " + greatBritainConfiguration.TradingBlocConfig.MemberCountry.GetType());
// A List of 'Country' is deserialized to the wrong type, depending on what '[XmlElement]' tag is listed first.
Console.WriteLine("Great Britain Countries Type " + greatBritainConfiguration.TradingBlocConfig.MemberCountries[0].GetType());
var euConfiguration = BuildConfig<TradingBlocConfiguration>(euConfig);
Console.WriteLine("EU Country Type " + euConfiguration.TradingBlocConfig.MemberCountry.GetType());
Console.WriteLine("EU Countries Type " + euConfiguration.TradingBlocConfig.MemberCountries[0].GetType());
Console.ReadLine();
}
private static T BuildConfig<T>(XDocument doc) where T : class
{
var stream = new MemoryStream();
doc.Save(stream);
T result;
using (var reader = new StreamReader(stream))
{
stream.Position = 0;
var xs = new XmlSerializer(typeof(T), new Type[] { typeof(GB.GreatBritain.Country) });
result = (T)xs.Deserialize(reader);
}
return result;
}
}
[XmlRoot("TradingBlocConfiguration")]
public sealed class TradingBlocConfiguration
{
[XmlElement("GreatBritain", typeof(GB.GreatBritain), Namespace = "GB")]
[XmlElement("EuropeanUnion", typeof(EU.EuropeanUnion), Namespace = "EU")]
public TradingBloc TradingBlocConfig { get; set; }
}
[XmlRoot]
[XmlInclude(typeof(GB.GreatBritain))]
[XmlInclude(typeof(EU.EuropeanUnion))]
public class BaseCountry { }
public abstract class TradingBloc
{
[XmlIgnore]
public abstract List<BaseCountry> MemberCountries { get; set; }
[XmlIgnore]
public abstract BaseCountry MemberCountry { get; set; }
}
namespace GB
{
[XmlRoot("GreatBritain")]
public class GreatBritain : TradingBloc
{
[XmlElement("Country", typeof(Country))]
public override BaseCountry MemberCountry { get; set; }
[XmlArray("Countries")]
[XmlArrayItem("Country", typeof(Country))]
public override List<BaseCountry> MemberCountries { get; set; }
[XmlRoot(Namespace = "GB")]
public class Country : BaseCountry { }
}
}
namespace EU
{
[XmlRoot("EuropeanUnion")]
public class EuropeanUnion : TradingBloc
{
[XmlElement("Country", typeof(Country))]
public override BaseCountry MemberCountry { get; set; }
[XmlArray("Countries")]
[XmlArrayItem("Country", typeof(Country))]
public override List<BaseCountry> MemberCountries { get; set; }
[XmlRoot(Namespace = "EU")]
public class Country : BaseCountry { }
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.