수색…


비고

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">

BaseContainer 유형에 선언 된 속성 유형에 해당하고 실제로 제공되는 인스턴스 유형은 Derived 입니다.

여기에 바이올린 작업 예제 가있다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow