.NET Framework
XmlSerializer
수색…
비고
XmlSerializer
를 사용하여 HTML
을 구문 분석하지 마십시오. 이를 위해 특수 라이브러리는 HTML Agility Pack
객체 직렬화
public void SerializeFoo(string fileName, Foo foo)
{
var serializer = new XmlSerializer(typeof(Foo));
using (var stream = File.Open(fileName, FileMode.Create))
{
serializer.Serialize(stream, foo);
}
}
객체 직렬화 해제
public Foo DeserializeFoo(string fileName)
{
var serializer = new XmlSerializer(typeof(Foo));
using (var stream = File.OpenRead(fileName))
{
return (Foo)serializer.Deserialize(stream);
}
}
동작 : 요소 이름을 속성에 매핑
<Foo>
<Dog/>
</Foo>
public class Foo
{
// Using XmlElement
[XmlElement(Name="Dog")]
public Animal Cat { get; set; }
}
동작 : 배열 이름을 속성에 매핑 (XmlArray)
<Store>
<Articles>
<Product/>
<Product/>
</Articles>
</Store>
public class Store
{
[XmlArray("Articles")]
public List<Product> Products {get; set; }
}
형식 지정 : 사용자 정의 DateTime 형식
public class Dog
{
private const string _birthStringFormat = "yyyy-MM-dd";
[XmlIgnore]
public DateTime Birth {get; set;}
[XmlElement(ElementName="Birth")]
public string BirthString
{
get { return Birth.ToString(_birthStringFormat); }
set { Birth = DateTime.ParseExact(value, _birthStringFormat, CultureInfo.InvariantCulture); }
}
}
동적으로 지정된 파생 형식을 사용하여 여러 개의 serializer를 효율적으로 작성
우리가 온 곳
경우에 따라 XmlSerializer 프레임 워크에 필요한 모든 필수 메타 데이터를 특성에 제공 할 수없는 경우도 있습니다. 직렬화 된 객체의 기본 클래스가 있다고 가정하고, 파생 클래스 중 일부는 기본 클래스에서 알 수없는 것입니다. 기본 유형의 디자인 타임에 모르는 모든 클래스에 대해 속성을 배치 할 수 없습니다. 우리는 파생 된 클래스의 일부를 개발하는 다른 팀을 가질 수 있습니다.
우리는 무엇을 할 수 있는가?
우리는 new XmlSerializer(type, knownTypes)
사용할 수 있지만 적어도 N 개의 serializer에 대해서는 O (N ^ 2) 연산이되어야합니다. 적어도 인수에 제공된 모든 유형을 발견해야합니다.
// Beware of the N^2 in terms of the number of types.
var allSerializers = allTypes.Select(t => new XmlSerializer(t, allTypes));
var serializerDictionary = Enumerable.Range(0, allTypes.Length)
.ToDictionary (i => allTypes[i], i => allSerializers[i])
이 예제에서 기본 형식은 OOP에서 정상적인 파생 형식을 인식하지 못합니다.
효율적으로 수행하기
다행히도이 특별한 문제를 해결하는 방법이 있습니다. 여러 개의 serializer에 대해 알려진 유형을 효율적으로 제공합니다.
System.Xml.Serialization.XmlSerializer.FromTypes 메서드 (유형 [])
FromTypes 메서드를 사용하면 Type 개체의 배열을 처리하기위한 XmlSerializer 개체의 배열을 효율적으로 만들 수 있습니다.
var allSerializers = XmlSerializer.FromTypes(allTypes);
var serializerDictionary = Enumerable.Range(0, allTypes.Length)
.ToDictionary(i => allTypes[i], i => allSerializers[i]);
다음은 완전한 코드 샘플입니다.
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using System.Linq;
using System.Linq;
public class Program
{
public class Container
{
public Base Base { get; set; }
}
public class Base
{
public int JustSomePropInBase { get; set; }
}
public class Derived : Base
{
public int JustSomePropInDerived { get; set; }
}
public void Main()
{
var sampleObject = new Container { Base = new Derived() };
var allTypes = new[] { typeof(Container), typeof(Base), typeof(Derived) };
Console.WriteLine("Trying to serialize without a derived class metadata:");
SetupSerializers(allTypes.Except(new[] { typeof(Derived) }).ToArray());
try
{
Serialize(sampleObject);
}
catch (InvalidOperationException e)
{
Console.WriteLine();
Console.WriteLine("This error was anticipated,");
Console.WriteLine("we have not supplied a derived class.");
Console.WriteLine(e);
}
Console.WriteLine("Now trying to serialize with all of the type information:");
SetupSerializers(allTypes);
Serialize(sampleObject);
Console.WriteLine();
Console.WriteLine("Slides down well this time!");
}
static void Serialize<T>(T o)
{
serializerDictionary[typeof(T)].Serialize(Console.Out, o);
}
private static Dictionary<Type, XmlSerializer> serializerDictionary;
static void SetupSerializers(Type[] allTypes)
{
var allSerializers = XmlSerializer.FromTypes(allTypes);
serializerDictionary = Enumerable.Range(0, allTypes.Length)
.ToDictionary(i => allTypes[i], i => allSerializers[i]);
}
}
산출:
Trying to serialize without a derived class metadata:
<?xml version="1.0" encoding="utf-16"?>
<Container xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
This error was anticipated,
we have not supplied a derived class.
System.InvalidOperationException: There was an error generating the XML document. ---> System.InvalidOperationException: The type Program+Derived was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write2_Base(String n, String ns, Base o, Boolean isNullable, Boolean needType)
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write3_Container(String n, String ns, Container o, Boolean isNullable, Boolean needType)
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write4_Container(Object o)
at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
--- End of inner exception stack trace ---
at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle)
at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces)
at Program.Serialize[T](T o)
at Program.Main()
Now trying to serialize with all of the type information:
<?xml version="1.0" encoding="utf-16"?>
<Container xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Base xsi:type="Derived">
<JustSomePropInBase>0</JustSomePropInBase>
<JustSomePropInDerived>0</JustSomePropInDerived>
</Base>
</Container>
Slides down well this time!
결과물
이 오류 메시지는 우리가 피하려고했던 것 (또는 일부 시나리오에서는 할 수없는 것)을 권장합니다 - 기본 클래스에서 파생 된 유형 참조 :
Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.
XML에서 파생 클래스를 얻는 방법은 다음과 같습니다.
<Base xsi:type="Derived">
Base
는 Container
유형에 선언 된 속성 유형에 해당하고 실제로 제공되는 인스턴스 유형은 Derived
입니다.