Używamy XmlSerializer
i chcę zapewnić niestandardową serializację dla niektórych klas. Jednak nie zawsze mam możliwość modyfikowania kodu źródłowego danej klasy, w przeciwnym razie mógłbym po prostu dokonać implementacji IXmlSerializable
. Czy jest jakiś sposób to zrobić?Czy mogę zapewnić niestandardową serializację dla XmlSerializer bez implementacji IXmlSerializable?
Czy mogę zapewnić niestandardową serializację dla XmlSerializer bez implementacji IXmlSerializable?
Odpowiedz
Oto prosty przykład pomocnika deserializowania Proxy:
przypisany typ, że nie możemy bezpośrednio kontrolować serializacji na poziomie klasy:
public sealed class Class //contrived example
{
public string Property {get;set;}
}
a xml musimy deserializowania z:
<Class>
<Property>Value</Property>
</Class>
Można utworzyć typ proxy, aby ręcznie przeprowadzić proces deserializacji typu docelowego:
[XmlRoot("Class")] // <-- Very important
public sealed class ClassSerializerProxy : IXmlSerializable
{
public Class ClassValue {get;set;}
public System.Xml.Schema.XmlSchema GetSchema(){return null;}
public void WriteXml(System.Xml.XmlWriter writer){}
public void ReadXml(System.Xml.XmlReader reader)
{
var x = XElement.ReadFrom(reader) as XElement;
this.ClassValue = new Class();
//again this is a simple contrived example
this.ClassValue.Property = x.XPathSelectElement("Property").Value;
}
}
użycia:
void Main()
{
// get the xml value somehow
var xdoc= XDocument.Parse(@"<Class><Property>Value</Property></Class>");
// deserialize the xml into the proxy type
var proxy = Deserialize<ClassSerializerProxy>(xdoc);
// read the resulting value
var value = proxy.ClassValue;
}
public object Deserialize(XDocument xmlDocument, Type DeserializeToType)
{
XmlSerializer xmlSerializer = new XmlSerializer(DeserializeToType);
using (XmlReader reader = xmlDocument.CreateReader())
return xmlSerializer.Deserialize(reader);
}
teraz rzucać w niektórych leków generycznych i metodę rozszerzenia, a my możemy oczyścić witrynie Up Call trochę dla końcowego (z wyjątkiem Obsługa wyjątków) wersji:
Zastosowanie:
void Main()
{
var xml = @"<Class><Property>Value</Property></Class>";
var value = xml.DeserializeWithProxy<ClassSerializerProxy,Class>();
value.Dump();
}
Twój typ instancji:
public sealed class Class
{
public string Property {get;set;}
}
interfejs że typy proxy musi implementować
public interface ISerializerProxy<TInstanceType> where TInstanceType : class
{
TInstanceType Value { get; }
}
Przykład Pełnomocnik obecnie wprowadza nowy interfejs
[XmlRoot("Class")]
public sealed class ClassSerializerProxy : IXmlSerializable, ISerializerProxy<Class>
{
public Class Value {get;set;}
public System.Xml.Schema.XmlSchema GetSchema(){return null;}
public void WriteXml(System.Xml.XmlWriter writer){}
public void ReadXml(System.Xml.XmlReader reader)
{
var x = XElement.ReadFrom(reader) as XElement;
this.Value = new Class();
this.Value.Property = x.XPathSelectElement("Property").Value;
}
}
Sposób deserializacji jest teraz metodę rozszerzenia na string
i może być używany z dowolnym proxy rodzaj.
public static class ExtensionMethods
{
public static TInstanceType DeserializeWithProxy<TProxyType,TInstanceType>(this string xml)
where TProxyType : ISerializerProxy<TInstanceType>
where TInstanceType : class
{
using (XmlReader reader = XDocument.Parse(xml).CreateReader())
{
var xmlSerializer = new XmlSerializer(typeof(TProxyType));
return (xmlSerializer.Deserialize(reader) as ISerializerProxy<TInstanceType>).Value;
}
}
}
Czy istnieje sposób użycia tego podejścia, jeśli mam duże drzewo obiektów i chcę użyć domyślnej serializacji dla drzewa jako całości, ale niestandardową serializację dla niektórych liści? Jeśli mam dostęp do źródła, mogę sprawić, by te liście zaimplementowały IXmlSerializable i umieściły tam niestandardową serializację. Ale jeśli nie mogę zmodyfikować liści, czy muszę napisać kod serializacji dla całego drzewa? A może w jakiś sposób celuję w mały podzbiór klas problemów? – Rob
@asawyer To jest świetna odpowiedź! Zdecydowałem się również na wdrożenie funkcji WriteXml, ponieważ moja prawdziwa klasa nie jest sama w sobie możliwa do serializowania. Składa się z zestawu akcesorów tylko do odczytu, które można ustawić tylko za pomocą konstruktora. –
@nadephette Jestem bardzo szczęśliwy, że mogłem pomóc! – asawyer
wiem można zdobić zajęcia z różnych XmlAttributes (jak '' XmlArray' XmlElement', itp), ale pytasz konkretnie o tym, jak sterować wyjściem XML klas niemodyfikowalne? –
Używam klas "proxy", które implikują IXmlSerializable z podaną nazwą głównego znacznika i używają funkcji ReadXml do konstruowania rzeczywistej wartości bazowej, która jest następnie eksponowana w publicznej własności. – asawyer
Cóż, istnieje przeciążenie konstruktora (http://msdn.microsoft.com/en-us/library/65k4wece.aspx), które pozwala zastąpić atrybuty używane w typach, ale nie wiem, czy to pozwala zmienić zachowanie/wynik 'IXmlSerializable.ReadXml'. EDYCJA: Czy można oddzielić obawy związane z serializacją między obiektami biznesowymi a obiektami stron trzecich? –