객체를 문자열로 직렬화


311

Object를 파일에 저장하는 방법은 다음과 같습니다.

// Save an object out to the disk
public static void SerializeObject<T>(this T toSerialize, String filename)
{
    XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType());
    TextWriter textWriter = new StreamWriter(filename);

    xmlSerializer.Serialize(textWriter, toSerialize);
    textWriter.Close();
}

나는 그것을 쓰지 않았다고 고백한다 (타입 매개 변수를 취하는 확장 메소드로만 변환했다).

이제 XML을 파일로 저장하지 않고 문자열로 다시 제공해야합니다. 나는 그것을 조사하고 있지만 아직 이해하지 못했습니다.

나는이 객체에 익숙한 사람에게는 이것이 정말 쉽다고 생각했습니다. 그렇지 않다면 결국 알아낼 것입니다.

답변:


530

StringWriter대신에를 사용하십시오 StreamWriter:

public static string SerializeObject<T>(this T toSerialize)
{
    XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType());

    using(StringWriter textWriter = new StringWriter())
    {
        xmlSerializer.Serialize(textWriter, toSerialize);
        return textWriter.ToString();
    }
}

참고로, XmlSerializer 생성자 toSerialize.GetType()대신에 사용하는 것이 중요 typeof(T)합니다. 첫 번째 클래스를 사용하는 경우 코드는 가능한 모든 서브 클래스 T(메소드에 유효한)를 포함하지만 후자를 사용하면에서 파생 된 유형을 전달할 때 실패 T합니다. 여기에,이 사항이 동기를 부여 몇 가지 예제 코드와 링크입니다 XmlSerializer를 던지는 Exception경우 typeof(T): 사용하면 파생 형의 기본 클래스에 정의되어 SerializeObject를 호출하는 방법에 파생 된 유형의 인스턴스를 전달하기 때문에, HTTP는 : // ideone .com / 1Z5J1 .

또한 Ideone은 Mono를 사용하여 코드를 실행합니다. 실제로 ExceptionMicrosoft .NET 런타임을 사용하면 MessageIdeone에 표시된 것과 다르지만 동일하게 실패합니다.


2
@JohnSaunders : 좋아,이 토론을 메타에 옮기는 것이 좋습니다. 여기입니다 난 그냥이 편집에 관한 메타 스택 오버플로에 게시 된 질문에 대한 링크 .
Fulvio

27
@ casperOne Guys, 내 대답을 엉망으로 중지하십시오. 요점은 StreamWriter 대신 StringWriter를 사용하는 것입니다. 다른 모든 것은 질문과 관련이 없습니다. typeof(T) vs 와 같은 세부 정보를 논의하려면 toSerialize.GetType()대답하지는 않지만 대답하십시오. 감사.
dtb

9
@dtb 죄송하지만 Stack Overflow는 공동으로 편집 됩니다. 또한 이 특정 답변은 meta에 대해 논의 되었으므로 편집은 유효합니다. 동의하지 않는 경우 답변이 특별한 경우라고 생각하여 공동으로 수정 해서는 안되는 이유에 대해 메타에 대한 해당 게시물에 회신 해주세요 .
casperOne

2
코드 적으로 이것은 내가 본 가장 짧은 예입니다. +1
froggythefrog

13
StringWriter는 IDisposable을 구현하므로 using 블록으로 묶어야합니다.
TrueWill

70

나는 이것이 실제로 질문에 대한 답변이 아니라는 것을 알고 있지만 질문에 대한 투표 수와 허용 된 답변을 바탕으로 사람들이 실제로 코드를 사용하여 객체를 문자열로 직렬화한다고 생각합니다.

XML 직렬화를 사용하면 불필요한 여분의 텍스트 쓰레기가 출력에 추가됩니다.

다음 수업

public class UserData
{
    public int UserId { get; set; }
}

그것은 생성

<?xml version="1.0" encoding="utf-16"?>
<UserData xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <UserId>0</UserId>
</UserData>

더 나은 솔루션은 JSON 직렬화를 사용하는 것입니다 ( Json.NET 중 최고 중 하나 ). 객체를 직렬화하려면

var userData = new UserData {UserId = 0};
var userDataString = JsonConvert.SerializeObject(userData);

객체를 역 직렬화하려면

var userData = JsonConvert.DeserializeObject<UserData>(userDataString);

직렬화 된 JSON 문자열은 다음과 같습니다.

{"UserId":0}

4
이 경우에는 맞지만 큰 XML 문서와 큰 JSON 문서를 보았습니다. JSON 문서는 거의 읽을 수 없습니다. 네임 스페이스와 같은 "쓰레기"를 억제 할 수 있습니다. 생성 된 XML은 JSON만큼 깨끗할 수 있지만 JSON보다 항상 더 읽기 쉽습니다. 가독성은 JSON보다 큰 장점입니다.
허먼 반 데르 블롬

2
"json online parser"를 온라인으로 검색하면 좀 더 사람이 읽을 수있는 방식으로 json 문자열을 형식화 할 수있는 온라인 json 파서가 있습니다.
xhafan

9
@HermanVanDerBlom XML이 JSON보다 더 읽기 쉽습니다? 세계에서 무엇을 피우고 있습니까? 이는 XML에 비해 JSON의 가장 큰 장점 중 하나입니다 . 높은 신호 / 잡음 비율로 인해 읽기 가 훨씬 쉽습니다. 간단히 말해서 JSON을 사용하면 내용이 태그 수프에 빠지지 않습니다!
메이슨 휠러

63

직렬화 및 역 직렬화 (XML / JSON) :

    public static T XmlDeserialize<T>(this string toDeserialize)
    {
        XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
        using(StringReader textReader = new StringReader(toDeserialize))
        {      
            return (T)xmlSerializer.Deserialize(textReader);
        }
    }

    public static string XmlSerialize<T>(this T toSerialize)
    {
        XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
        using(StringWriter textWriter = new StringWriter())
        {
            xmlSerializer.Serialize(textWriter, toSerialize);
            return textWriter.ToString();
        }
    }

    public static T JsonDeserialize<T>(this string toDeserialize)
    {
        return JsonConvert.DeserializeObject<T>(toDeserialize);
    }

    public static string JsonSerialize<T>(this T toSerialize)
    {
        return JsonConvert.SerializeObject(toSerialize);
    }

15
다른 답변과 달리 역 직렬화 방법을 보여주는 +1 감사!
deadlydog

6
하나의 사소한 변경은 객체 대신 T를 반환하고 DeserializeObject 함수에서 반환 된 객체를 T로 캐스팅하는 것입니다. 이렇게하면 일반 개체 대신 강력한 형식의 개체가 반환됩니다.
deadlydog

@ deadlydog에게 감사드립니다.
ADM-IT

3
TextWriter에는 호출해야하는 Dispose () 함수가 있습니다. 따라서 Using 문을 잊어 버렸습니다.
허먼 반 데르 블롬

38

코드 안전 정보

에 대해서는 허용 대답 , 그것을 사용하는 것이 중요합니다 toSerialize.GetType()대신 typeof(T)XmlSerializer생성자 : 후자를 사용하는 동안, 코드는 가능한 모든 시나리오를 다루고 첫 번째를 사용하는 경우 종종 실패합니다.

다음은 파생 된 형식의 기본 클래스에 정의 된 호출하는 메서드에 파생 된 형식의 인스턴스를 전달하기 때문에 사용 된 XmlSerializer경우 Exception을 발생시키면서이 문을 동기 부여하는 예제 코드가있는 링크입니다 . http : // ideone .com / 1Z5J1 . Ideone은 Mono를 사용하여 코드를 실행합니다. Microsoft .NET 런타임을 사용하는 실제 예외는 Ideone에 표시된 것과 다른 Message를 갖지만 동일하게 실패합니다.typeof(T)SerializeObject<T>()

완성도를 위해서 난 그냥 경우, 향후 참조를 위해 여기에 전체 코드 샘플을 게시 Ideone (I 코드를 게시) 미래에 사용할 수 없게됩니다 :

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

public class Test
{
    public static void Main()
    {
        Sub subInstance = new Sub();
        Console.WriteLine(subInstance.TestMethod());
    }

    public class Super
    {
        public string TestMethod() {
            return this.SerializeObject();
        }
    }

    public class Sub : Super
    {
    }
}

public static class TestExt {
    public static string SerializeObject<T>(this T toSerialize)
    {
        Console.WriteLine(typeof(T).Name);             // PRINTS: "Super", the base/superclass -- Expected output is "Sub" instead
        Console.WriteLine(toSerialize.GetType().Name); // PRINTS: "Sub", the derived/subclass

        XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
        StringWriter textWriter = new StringWriter();

        // And now...this will throw and Exception!
        // Changing new XmlSerializer(typeof(T)) to new XmlSerializer(subInstance.GetType()); 
        // solves the problem
        xmlSerializer.Serialize(textWriter, toSerialize);
        return textWriter.ToString();
    }
}

12
또한 using (StringWriter textWriter = new StringWriter() {}물체를 올바르게 닫거나 폐기 해야 합니다.
Amicable

나는 당신에게 @Amicable에 완전히 동의합니다! 객체 유형에 관한 모든 요점을 강조하기 위해 코드 샘플을 가능한 한 OP에 가깝게 유지하려고했습니다. 어쨌든 그것의 좋은는 것을 아무도 기억 using문은 우리에게 우리의 사랑에 모두 가장 좋은 친구입니다 IDisposable구현하는 객체)
풀비

"확장 메소드를 사용하면 새로운 파생 유형을 작성하거나 재 컴파일하거나 원래 유형을 수정하지 않고 기존 유형에 메소드를"추가 "할 수 있습니다." msdn.microsoft.com/en-us/library/bb383977.aspx
Adrian

12

내 2p ...

        string Serialise<T>(T serialisableObject)
        {
            var xmlSerializer = new XmlSerializer(serialisableObject.GetType());

            using (var ms = new MemoryStream())
            {
                using (var xw = XmlWriter.Create(ms, 
                    new XmlWriterSettings()
                        {
                            Encoding = new UTF8Encoding(false),
                            Indent = true,
                            NewLineOnAttributes = true,
                        }))
                {
                    xmlSerializer.Serialize(xw,serialisableObject);
                    return Encoding.UTF8.GetString(ms.ToArray());
                }
            }
        }

XmlWriterSettings () 사용시 +1 직렬화 된 XML이 예쁜 인쇄물로 공간을 낭비하지 않고 Indent = false 및 NewLineOnAttributes = false 설정으로 작업을 수행하지 않기를 원했습니다.
리 리처드슨

@LeeRichardson에게 감사드립니다-.net 아래의 XmlWriter의 기본값은 UTF16으로 설정되어 있습니다.
oPless

이 메모리 스트림 조합을 사용하고 인코딩을 통해 가져 오기 GetString은 Preamble / BOM을 문자열의 첫 번째 문자로 포함합니다. 또한 참조 stackoverflow.com/questions/11701341/...
Jamee

@Jamee "인코딩 = UTF8Encoding (false)"은 docs.microsoft.com/en-us/dotnet/api / ...에 따라 BOM을 쓰지 않음을 의미합니다. .net4 이후로이 동작이 변경 되었습니까?
oPless

4
public static string SerializeObject<T>(T objectToSerialize)
        {
            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            MemoryStream memStr = new MemoryStream();

            try
            {
                bf.Serialize(memStr, objectToSerialize);
                memStr.Position = 0;

                return Convert.ToBase64String(memStr.ToArray());
            }
            finally
            {
                memStr.Close();
            }
        }

        public static T DerializeObject<T>(string objectToDerialize)
        {
            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            byte[] byteArray = Convert.FromBase64String(objectToDerialize);
            MemoryStream memStr = new MemoryStream(byteArray);

            try
            {
                return (T)bf.Deserialize(memStr);
            }
            finally
            {
                memStr.Close();
            }
        }

1

xhafan이 제안한 JSONConvert 메소드를 사용할 수 없습니다

.Net 4.5에서는 "System.Web.Extensions"어셈블리 참조를 추가 한 후에도 여전히 JSONConvert에 액세스 할 수 없었습니다.

그러나 참조를 추가하면 다음을 사용하여 동일한 문자열을 출력 할 수 있습니다.

JavaScriptSerializer js = new JavaScriptSerializer();
string jsonstring = js.Serialize(yourClassObject);

2
JSONConvert 클래스는 NewtonSoft.Json 네임 스페이스에 있습니다. VS의 패키지 관리자로 이동 한 다음 NewtonSoft.Json 패키지를 다운로드하십시오
Amir Shrestha

1

이 조작 된 코드를 승인 된 답변과 공유해야 할 것 같은 느낌이 들었습니다. 평판이 없어서 댓글을 달 수 없습니다 ..

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

namespace ObjectSerialization
{
    public static class ObjectSerialization
    {
        // THIS: (C): /programming/2434534/serialize-an-object-to-string
        /// <summary>
        /// A helper to serialize an object to a string containing XML data of the object.
        /// </summary>
        /// <typeparam name="T">An object to serialize to a XML data string.</typeparam>
        /// <param name="toSerialize">A helper method for any type of object to be serialized to a XML data string.</param>
        /// <returns>A string containing XML data of the object.</returns>
        public static string SerializeObject<T>(this T toSerialize)
        {
            // create an instance of a XmlSerializer class with the typeof(T)..
            XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType());

            // using is necessary with classes which implement the IDisposable interface..
            using (StringWriter stringWriter = new StringWriter())
            {
                // serialize a class to a StringWriter class instance..
                xmlSerializer.Serialize(stringWriter, toSerialize); // a base class of the StringWriter instance is TextWriter..
                return stringWriter.ToString(); // return the value..
            }
        }

        // THIS: (C): VPKSoft, 2018, https://www.vpksoft.net
        /// <summary>
        /// Deserializes an object which is saved to an XML data string. If the object has no instance a new object will be constructed if possible.
        /// <note type="note">An exception will occur if a null reference is called an no valid constructor of the class is available.</note>
        /// </summary>
        /// <typeparam name="T">An object to deserialize from a XML data string.</typeparam>
        /// <param name="toDeserialize">An object of which XML data to deserialize. If the object is null a a default constructor is called.</param>
        /// <param name="xmlData">A string containing a serialized XML data do deserialize.</param>
        /// <returns>An object which is deserialized from the XML data string.</returns>
        public static T DeserializeObject<T>(this T toDeserialize, string xmlData)
        {
            // if a null instance of an object called this try to create a "default" instance for it with typeof(T),
            // this will throw an exception no useful constructor is found..
            object voidInstance = toDeserialize == null ? Activator.CreateInstance(typeof(T)) : toDeserialize;

            // create an instance of a XmlSerializer class with the typeof(T)..
            XmlSerializer xmlSerializer = new XmlSerializer(voidInstance.GetType());

            // construct a StringReader class instance of the given xmlData parameter to be deserialized by the XmlSerializer class instance..
            using (StringReader stringReader = new StringReader(xmlData))
            {
                // return the "new" object deserialized via the XmlSerializer class instance..
                return (T)xmlSerializer.Deserialize(stringReader);
            }
        }

        // THIS: (C): VPKSoft, 2018, https://www.vpksoft.net
        /// <summary>
        /// Deserializes an object which is saved to an XML data string.
        /// </summary>
        /// <param name="toDeserialize">A type of an object of which XML data to deserialize.</param>
        /// <param name="xmlData">A string containing a serialized XML data do deserialize.</param>
        /// <returns>An object which is deserialized from the XML data string.</returns>
        public static object DeserializeObject(Type toDeserialize, string xmlData)
        {
            // create an instance of a XmlSerializer class with the given type toDeserialize..
            XmlSerializer xmlSerializer = new XmlSerializer(toDeserialize);

            // construct a StringReader class instance of the given xmlData parameter to be deserialized by the XmlSerializer class instance..
            using (StringReader stringReader = new StringReader(xmlData))
            {
                // return the "new" object deserialized via the XmlSerializer class instance..
                return xmlSerializer.Deserialize(stringReader);
            }
        }
    }
}


나는 이것이 오래되었다는 것을 알고 있지만, 당신이 정말로 좋은 대답을했기 때문에 PR에 대한 코드 검토를 한 것처럼 작은 의견을 추가 할 것입니다. 제네릭을 사용할 때 T에 제약이 있어야합니다. 그것은 직렬화를 기준으로 빌려 자신을 깔끔한 일을 유지, 그리고 모든 객체를 코드베이스와 프레임 워크하는 데 도움이
프랭크 R. 저자 Haugen

-1

드문 경우지만 자체 문자열 직렬화를 구현할 수 있습니다.

그러나 당신이하고있는 일을 알지 못하면 아마도 나쁜 생각입니다. (예 : 배치 파일로 I / O 직렬화)

그와 같은 것이 트릭을 수행하고 (손으로 / 편집으로 쉽게 편집 할 수는 있지만) 이름에 줄 바꿈이 포함되지 않은 것처럼 더 많은 검사를 수행해야합니다.

public string name {get;set;}
public int age {get;set;}

Person(string serializedPerson) 
{
    string[] tmpArray = serializedPerson.Split('\n');
    if(tmpArray.Length>2 && tmpArray[0].Equals("#")){
        this.name=tmpArray[1];
        this.age=int.TryParse(tmpArray[2]);
    }else{
        throw new ArgumentException("Not a valid serialization of a person");
    }
}

public string SerializeToString()
{
    return "#\n" +
           name + "\n" + 
           age;
}

-1

[VB]

Public Function XmlSerializeObject(ByVal obj As Object) As String

    Dim xmlStr As String = String.Empty

    Dim settings As New XmlWriterSettings()
    settings.Indent = False
    settings.OmitXmlDeclaration = True
    settings.NewLineChars = String.Empty
    settings.NewLineHandling = NewLineHandling.None

    Using stringWriter As New StringWriter()
        Using xmlWriter__1 As XmlWriter = XmlWriter.Create(stringWriter, settings)

            Dim serializer As New XmlSerializer(obj.[GetType]())
            serializer.Serialize(xmlWriter__1, obj)

            xmlStr = stringWriter.ToString()
            xmlWriter__1.Close()
        End Using

        stringWriter.Close()
    End Using

    Return xmlStr.ToString
End Function

Public Function XmlDeserializeObject(ByVal data As [String], ByVal objType As Type) As Object

    Dim xmlSer As New System.Xml.Serialization.XmlSerializer(objType)
    Dim reader As TextReader = New StringReader(data)

    Dim obj As New Object
    obj = DirectCast(xmlSer.Deserialize(reader), Object)
    Return obj
End Function

[씨#]

public string XmlSerializeObject(object obj)
{
    string xmlStr = String.Empty;
    XmlWriterSettings settings = new XmlWriterSettings();
    settings.Indent = false;
    settings.OmitXmlDeclaration = true;
    settings.NewLineChars = String.Empty;
    settings.NewLineHandling = NewLineHandling.None;

    using (StringWriter stringWriter = new StringWriter())
    {
        using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter, settings))
        {
            XmlSerializer serializer = new XmlSerializer( obj.GetType());
            serializer.Serialize(xmlWriter, obj);
            xmlStr = stringWriter.ToString();
            xmlWriter.Close();
        }
    }
    return xmlStr.ToString(); 
}

public object XmlDeserializeObject(string data, Type objType)
{
    XmlSerializer xmlSer = new XmlSerializer(objType);
    StringReader reader = new StringReader(data);

    object obj = new object();
    obj = (object)(xmlSer.Deserialize(reader));
    return obj;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.