Reputation: 159
I have some legacy code that used ArrayList's to serialize data out, this yields xml types of <anyType xsi:type="SomeType">
. They all share the same data type so is pointless and yields code that is a mess.
Is there any elegant way of coercing this type of data in to a List when deserializing, short of pre-sanitizing the xml before it's deserialized?
Basically, I want to turn code from
[Serializable()]
public class SomeContainer
{
public ArrayList SomeDataList1
public ArrayList SomeDataList2
public ArrayList SomeDataList3
public ArrayList SomeDataList4
}
to
[Serializable()]
public class SomeContainer
{
public List<SomeType1> SomeDataList1
public List<SomeType2> SomeDataList2
public List<SomeType3> SomeDataList3
public List<SomeType4> SomeDataList4
}
So I'm interested in the ArrayList -> List translation, rather than the container.
Upvotes: 0
Views: 552
Reputation: 159
In regards to the comment I left for the answer by Sean Skelly.
public class AnyList<T> : IEnumerable where T : class
{
List<T> holder = new List<T>();
public int Count()
{
return holder.Count;
}
public void Add(object objectToAdd)
{
T typedObjectToAdd = objectToAdd as T;
if (typedObjectToAdd != null)
{
holder.Add(typedObjectToAdd);
}
// If you can't guarantee the input data, should perhaps inform some data will be skipped.
}
public IEnumerator GetEnumerator()
{
return holder.GetEnumerator();
}
}
And XmlInclude is important, as it might deduce by itself, or might not and just pass through an XmlNode instead, which may or may not be useful for custom transforms.
[Serializable()]
[XmlInclude(typeof(SomeType1))]
[XmlInclude(typeof(SomeType2))]
[XmlInclude(typeof(SomeType3))]
[XmlInclude(typeof(SomeType4))]
public class SomeContainer
{
public AnyList<SomeType1> SomeDataList1
public AnyList<SomeType2> SomeDataList2
public AnyList<SomeType3> SomeDataList3
public AnyList<SomeType4> SomeDataList4
}
This is clean enough meaning I can change back to List once the data has normalized.
Would have been better if C# had generic attributes.
Upvotes: 0
Reputation: 1344
If you mark your classes with the right XML attributes, you can get your SomeContainer
class to mimic the behavior of ArrayList
for deserializing XML.
You may not care, but you would need to have your class implement IEnumerable
if you also want your class to be serialized the same as with ArrayList.
See the example below for full serialize/deserialize that looks the same as ArrayList. If you want, you can remove the IEnumerable
implementation, and you will see that the serialization changes. Deserializing with "anyType" still works without implementing IEnumerable
, though.
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
namespace SomeNamespace
{
[XmlType(nameof(SomeContainer))]
[XmlInclude(typeof(SomeType))]
public class SomeContainer : IEnumerable
{
[XmlArrayItem(typeof(SomeType))]
public List<SomeType> SomeDataList = new List<SomeType>();
public void Add(object o)
{
SomeDataList.Add(o as SomeType);
}
public int Count()
{
return SomeDataList.Count;
}
public IEnumerator GetEnumerator()
{
return SomeDataList.GetEnumerator();
}
}
public class SomeType
{
public string Name { get; set; } = "SomeName";
}
class Program
{
static void Main()
{
SomeContainer s1 = new SomeContainer();
s1.SomeDataList.Add(new SomeType());
string tempPath = "c:\\temp\\test.xml";
XmlSerializer serializer = new XmlSerializer(typeof(SomeContainer));
// serialize
using (StreamWriter sw = new StreamWriter(tempPath))
{
serializer.Serialize(sw, s1);
}
/* Produces the following XML:
<?xml version="1.0" encoding="utf-8"?>
<SomeContainer xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<anyType xsi:type="SomeType">
<Name>SomeName</Name>
</anyType>
</SomeContainer>
*/
// deserialize
SomeContainer s2;
using (StreamReader sr = new StreamReader(tempPath))
{
s2 = (SomeContainer)serializer.Deserialize(sr);
}
// check contents of s2 as you please
}
}
}
(@Flydog57's comment was right, and came literally as I was typing this.)
Upvotes: 2