我必须编写自己的反序列化器,因为XmlSerializer和DataContractSerializer不能满足我的需求。所以,这是我的反序列化器的基础:
static BaseElement ParseXml(XElement element)
{
var e = (Element)Activator.CreateInstance(Type.GetType("Elements." + element.Name));
foreach (var attr in element.Attributes())
{
var property = e.GetType().GetProperty(attr.Name.LocalName);
property.SetValue(e, Convert.ChangeType(attr.Value, property.PropertyType), null);
}
foreach (var x in element.Elements())
e.Elements.Add(ParseXml(x));
return e;
}
BaseElement类:
public abstract class BaseElement
{
public BaseElement()
{
Elements = new List<Element>();
}
public IList<Element> Elements
{
get;
set;
}
}
唯一的限制是,我不能拥有自定义类型属性,因为我无法使用Convert.ChangeType转换为自定义类型。关于如何解决这个问题的任何想法?
感谢。
答案 0 :(得分:0)
您可以通过实施IConvertible
界面使自己的自定义类型可转换。 Here's来自MSDN的一个例子。
答案 1 :(得分:0)
IConvertible没有定义如何使用字符串来创建在这种情况下需要的类型的实例。你可以创建一个转换构造函数,但是,在尝试通过反射设置值时,由于某种原因,它会自动调用。因此,您必须手动查找转换构造函数并在适用时调用它。这是关于我如何做到的:
namespace Elements
{
class Program
{
static void Main(string[] args)
{
System.Xml.Linq.XElement sample = System.Xml.Linq.XElement.Parse(
"<Element a=\"3\" b=\"Havarti\" modeSel=\"Complex\" />");
Element c1 = Element.ParseXml(sample);
}
}
public class ModeSelection
{
private int mode;
public static explicit operator ModeSelection(string value)
{
ModeSelection result = new ModeSelection();
if (String.Compare(value, "Simple", true) == 0)
result.mode = 1;
else if (String.Compare(value, "Complex", true) == 0)
result.mode = 2;
else if (!int.TryParse(value, out result.mode))
throw new FormatException("Cannot convert value to type " + result.GetType().Name);
return result;
}
string Description
{
get
{
switch (mode)
{
case 1:
return "Simple";
case 2:
return "Complex";
default:
return "Other";
}
}
}
}
public abstract class BaseElement<T> where T : BaseElement<T>, new()
{
public static T ParseXml(System.Xml.Linq.XElement element)
{
var e = (T)Activator.CreateInstance(Type.GetType("Elements." + element.Name));
Type[] convParamTypes = new Type[] {typeof(string)};
foreach (var attr in element.Attributes())
{
var property = e.GetType().GetProperty(attr.Name.LocalName);
System.Reflection.MethodInfo conv = property.PropertyType.GetMethod(
"op_Explicit", convParamTypes);
if (conv != null)
property.SetValue(e, conv.Invoke(null, new object[] {attr.Value}), null);
else
property.SetValue(e, Convert.ChangeType(attr.Value, property.PropertyType), null);
}
foreach (var x in element.Elements())
e.Elements.Add(ParseXml(x));
return e;
}
public BaseElement()
{
Elements = new List<T>();
}
public IList<T> Elements
{
get;
set;
}
}
public class Element : BaseElement<Element>
{
int _a;
string _b;
ModeSelection _modeSel;
public int a
{
get
{
return _a;
}
set
{
_a = value;
}
}
public string b
{
get
{
return _b;
}
set
{
_b = value;
}
}
public ModeSelection modeSel
{
get
{
return _modeSel;
}
set
{
_modeSel = value;
}
}
}
}