JMc*_*JMc 5 c# xml serialization xml-serialization xmlserializer
下面的程序是我在C#中反序列化XML时发现的一个问题的例子.我有两个单独的程序集,它们声明一个具有相同名称的类型,在下面的示例中为"Country".这些类型由XML命名空间区分.当我反序列化包含单个"Country"元素的配置文件时,将解析正确的"Country"类型.但是,如果我反序列化"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 { }
}
}
Run Code Online (Sandbox Code Playgroud)
如果您运行上面的示例,则输出为:
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
Run Code Online (Sandbox Code Playgroud)
"英国国家类型"不正确.如果您更改TradingBlocConfiguration类中[XmlElement]属性的顺序,如:
[XmlRoot("TradingBlocConfiguration")]
public sealed class TradingBlocConfiguration
{
[XmlElement("EuropeanUnion", typeof(EU.EuropeanUnion))]
[XmlElement("GreatBritain", typeof(GB.GreatBritain))]
public TradingBloc TradingBlocConfig { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
然后结果变为:
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
Run Code Online (Sandbox Code Playgroud)
在这种情况下,英国看起来不错,但欧盟错了:).任何人都可以解释为什么List被反序列化为错误的类型?
解决方案是添加 xmlns 标签。下面更新的代码可以正常工作:
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 { }
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
204 次 |
| 最近记录: |