C'est tout simplement l'une des limites inhérentes déclaratif de sérialisation où le type d'informations n'est pas incorporé à l'intérieur de la sortie.
En essayant de convertir <Flibble Foo="10" />
de retour dans
public class Flibble { public object Foo { get; set; } }
Comment le sérialiseur de savoir si elle doit être un entier, une chaîne, d'un lit double (ou autre chose)...
Pour ce faire, vous disposez de plusieurs options, mais si vous avez vraiment ne savez pas jusqu'à exécution la manière la plus simple pour ce faire est susceptible d'être à l'aide de la XmlAttributeOverrides.
Malheureusement, cela ne fonctionne qu'avec les classes de base, pas d'interfaces. Le meilleur que vous pouvez faire est d'ignorer la propriété qui n'est pas suffisant pour vos besoins.
Si vous devez vraiment rester avec les interfaces, vous avez trois options réelles:
Masquer et de traiter avec elle dans une autre propriété
Laid, désagréable chaudière plaque et beaucoup de répétitions, mais la plupart des consommateurs de la classe n'aura pas à régler le problème:
[XmlIgnore()]
public object Foo { get; set; }
[(XmlElement("Foo")]
[EditorVisibile(EditorVisibility.Advanced)]
public string FooSerialized
{
get { /* code here to convert any type in Foo to string */ }
set { /* code to parse out of get and make an instance of the proper type*/ }
}
Cela est susceptible de devenir un entretien cauchemar...
Mettre En Œuvre IXmlSerializable
Semblable à la première option que vous prenez le contrôle total de choses, mais
- Pros
- Vous n'avez pas méchant "faux" propriétés de traîner.
- vous pouvez interagir directement avec la structure xml en ajoutant de la flexibilité et des versions
- Cons
- vous pouvez finir par avoir à re-mettre en œuvre la roue pour toutes les autres propriétés de la classe
Les problèmes de la duplication des efforts sont semblables à la première.
Modifier votre propriété à utiliser un type d'emballage
public sealed class XmlAnything<T> : IXmlSerializable
{
public XmlAnything() {}
public XmlAnything(T t) { this.Value = t;}
public T Value {get; set;}
public void WriteXml (XmlWriter writer)
{
if (Value == null)
{
writer.WriteAttributeString("type", "null");
return;
}
Type type = this.Value.GetType();
XmlSerializer serializer = new XmlSerializer(type);
writer.WriteAttributeString("type", type.AssemblyQualifiedName);
serializer.Serialize(writer, this.Value);
}
public void ReadXml(XmlReader reader)
{
if(!reader.HasAttributes)
throw new FormatException("expected a type attribute!");
string type = reader.GetAttribute("type");
reader.Read(); // consume the value
if (type == "null")
return;// leave T at default value
XmlSerializer serializer = new XmlSerializer(Type.GetType(type));
this.Value = (T)serializer.Deserialize(reader);
reader.ReadEndElement();
}
public XmlSchema GetSchema() { return(null); }
}
L'utilisation de ce impliquerait quelque chose comme (dans le projet P):
public namespace P
{
public interface IFoo {}
public class RealFoo : IFoo { public int X; }
public class OtherFoo : IFoo { public double X; }
public class Flibble
{
public XmlAnything<IFoo> Foo;
}
public static void Main(string[] args)
{
var x = new Flibble();
x.Foo = new XmlAnything<IFoo>(new RealFoo());
var s = new XmlSerializer(typeof(Flibble));
var sw = new StringWriter();
s.Serialize(sw, x);
Console.WriteLine(sw);
}
}
qui vous donne:
<?xml version="1.0" encoding="utf-16"?>
<MainClass
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Foo type="P.RealFoo, P, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<RealFoo>
<X>0</X>
</RealFoo>
</Foo>
</MainClass>
C'est évidemment plus difficile pour les utilisateurs de la classe mais évite beaucoup de la chaudière de la plaque.
Un juste milieu peut être la fusion de la XmlAnything idée dans le "backing" propriété du la première technique. De cette façon, la plupart de la gros du travail est fait pour vous, mais les consommateurs de la classe souffrent pas d'impact au-delà de la confusion avec l'introspection.