카테고리 보관물: C#

C#

객체를 XML로 직렬화 보이지만 XML 표현을 얻는

상속받은 C # 클래스가 있습니다. 개체를 성공적으로 “빌드”했습니다. 그러나 객체를 XML로 직렬화해야합니다. 쉬운 방법이 있습니까?

클래스가 직렬화를 위해 설정된 것처럼 보이지만 XML 표현을 얻는 방법을 잘 모르겠습니다. 내 수업 정의는 다음과 같습니다.

[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.1")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://www.domain.com/test")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "http://www.domain.com/test", IsNullable = false)]
public partial class MyObject
{
  ...
}

여기 내가 할 수 있다고 생각했지만 작동하지 않습니다.

MyObject o = new MyObject();
// Set o properties
string xml = o.ToString();

이 객체의 XML 표현을 어떻게 얻습니까?



답변

XML 직렬화에는 XmlSerializer를 사용해야합니다. 아래는 샘플 스 니펫입니다.

 XmlSerializer xsSubmit = new XmlSerializer(typeof(MyObject));
 var subReq = new MyObject();
 var xml = "";

 using(var sww = new StringWriter())
 {
     using(XmlWriter writer = XmlWriter.Create(sww))
     {
         xsSubmit.Serialize(writer, subReq);
         xml = sww.ToString(); // Your XML
     }
 }

답변

아래처럼 ref 변수를 사용하는 대신 문자열을 반환하도록 내 것을 수정했습니다.

public static string Serialize<T>(this T value)
{
    if (value == null)
    {
        return string.Empty;
    }
    try
    {
        var xmlserializer = new XmlSerializer(typeof(T));
        var stringWriter = new StringWriter();
        using (var writer = XmlWriter.Create(stringWriter))
        {
            xmlserializer.Serialize(writer, value);
            return stringWriter.ToString();
        }
    }
    catch (Exception ex)
    {
        throw new Exception("An error occurred", ex);
    }
}

사용법은 다음과 같습니다.

var xmlString = obj.Serialize();

답변

다음 함수는 System.Xml 네임 스페이스를 사용하여 XML 저장 함수를 추가하기 위해 모든 개체에 복사 할 수 있습니다.

/// <summary>
/// Saves to an xml file
/// </summary>
/// <param name="FileName">File path of the new xml file</param>
public void Save(string FileName)
{
    using (var writer = new System.IO.StreamWriter(FileName))
    {
        var serializer = new XmlSerializer(this.GetType());
        serializer.Serialize(writer, this);
        writer.Flush();
    }
}

저장된 파일에서 객체를 생성하려면 다음 기능을 추가하고 [ObjectType]을 생성 할 객체 유형으로 바꿉니다.

/// <summary>
/// Load an object from an xml file
/// </summary>
/// <param name="FileName">Xml file name</param>
/// <returns>The object created from the xml file</returns>
public static [ObjectType] Load(string FileName)
{
    using (var stream = System.IO.File.OpenRead(FileName))
    {
        var serializer = new XmlSerializer(typeof([ObjectType]));
        return serializer.Deserialize(stream) as [ObjectType];
    }
}

답변

확장 클래스 :

using System.IO;
using System.Xml;
using System.Xml.Serialization;

namespace MyProj.Extensions
{
    public static class XmlExtension
    {
        public static string Serialize<T>(this T value)
        {
            if (value == null) return string.Empty;

            var xmlSerializer = new XmlSerializer(typeof(T));

            using (var stringWriter = new StringWriter())
            {
                using (var xmlWriter = XmlWriter.Create(stringWriter,new XmlWriterSettings{Indent = true}))
                {
                    xmlSerializer.Serialize(xmlWriter, value);
                    return stringWriter.ToString();
                }
            }
        }
    }
}

용법:

Foo foo = new Foo{MyProperty="I have been serialized"};

string xml = foo.Serialize();

확장 메소드를 보유하고있는 파일에서 확장 메소드를 보유하고있는 네임 스페이스를 참조하면 작동합니다 (제 예에서는 다음과 같습니다 using MyProj.Extensions;)

확장 메소드를 특정 클래스 (예 :)에만 고유하게 만들려면 확장 메소드 FooT인수를 대체 할 수 있습니다 (예 :).

public static string Serialize(this Foo value){...}


답변

아래와 같은 함수를 사용하여 모든 객체에서 직렬화 된 XML을 얻을 수 있습니다.

public static bool Serialize<T>(T value, ref string serializeXml)
{
    if (value == null)
    {
        return false;
    }
    try
    {
        XmlSerializer xmlserializer = new XmlSerializer(typeof(T));
        StringWriter stringWriter = new StringWriter();
        XmlWriter writer = XmlWriter.Create(stringWriter);

        xmlserializer.Serialize(writer, value);

        serializeXml = stringWriter.ToString();

        writer.Close();
        return true;
    }
    catch (Exception ex)
    {
        return false;
    }
}

클라이언트에서 이것을 호출 할 수 있습니다.


답변

객체를 직렬화하려면 다음을 수행하십시오.

 using (StreamWriter myWriter = new StreamWriter(path, false))
 {
     XmlSerializer mySerializer = new XmlSerializer(typeof(your_object_type));
     mySerializer.Serialize(myWriter, objectToSerialize);
 }

또한 XmlSerializer가 작동하려면 매개 변수가없는 생성자가 필요합니다.


답변

Ben Gripka의 답변으로 시작하겠습니다.

public void Save(string FileName)
{
    using (var writer = new System.IO.StreamWriter(FileName))
    {
        var serializer = new XmlSerializer(this.GetType());
        serializer.Serialize(writer, this);
        writer.Flush();
    }
}

이 코드를 더 일찍 사용했습니다. 그러나 현실은이 솔루션이 약간 문제가 있음을 보여주었습니다. 일반적으로 대부분의 프로그래머는 저장시 설정을 직렬화하고로드시 설정을 직렬화 해제합니다. 이것은 낙관적 시나리오입니다. 어떤 이유로 인해 직렬화에 실패하면 파일이 부분적으로 작성되고 XML 파일이 완료되지 않아 유효하지 않습니다. 결과적으로 XML 역 직렬화가 작동하지 않고 시작시 응용 프로그램이 중단 될 수 있습니다. 파일이 크지 않으면 먼저 객체를 직렬화 MemoryStream한 다음 스트림을 파일에 쓰도록 제안 합니다. 이 경우는 복잡한 사용자 지정 직렬화가있는 경우 특히 중요합니다. 모든 사례를 테스트 할 수는 없습니다.

public void Save(string fileName)
{
    //first serialize the object to memory stream,
    //in case of exception, the original file is not corrupted
    using (MemoryStream ms = new MemoryStream())
    {
        var writer = new System.IO.StreamWriter(ms);
        var serializer = new XmlSerializer(this.GetType());
        serializer.Serialize(writer, this);
        writer.Flush();

        //if the serialization succeed, rewrite the file.
        File.WriteAllBytes(fileName, ms.ToArray());
    }
}

실제 시나리오에서 역 직렬화는 손상된 직렬화 파일로 계산해야하며, 때때로 발생합니다. Ben Gripka가 제공하는로드 기능이 좋습니다.

public static [ObjectType] Load(string fileName)
{
    using (var stream = System.IO.File.OpenRead(fileName))
    {
        var serializer = new XmlSerializer(typeof([ObjectType]));
        return serializer.Deserialize(stream) as [ObjectType];
    }
}

그리고 일부 복구 시나리오로 인해 랩핑 될 수 있습니다. 설정 파일 또는 문제 발생시 삭제할 수있는 기타 파일에 적합합니다.

public static [ObjectType] LoadWithRecovery(string fileName)
{
    try
    {
        return Load(fileName);
    }
    catch(Excetion)
    {
        File.Delete(fileName); //delete corrupted settings file
        return GetFactorySettings();
    }
}