オブジェクトを文字列にシリアル化する


311

オブジェクトをファイルに保存するには、次の方法があります。

// 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ます。派生型のインスタンスを、派生型の基本クラスで定義されているSerializeObjectを呼び出すメソッドに渡すのでXmlSerializerExceptionwhen typeof(T)がスローされ、このステートメントを動機付けるいくつかのサンプルコードとのリンクは次のとおりです。http:// ideone .com / 1Z5J1

また、IdeonはMonoを使用してコードを実行します。実際にExceptionMicrosoft .NETランタイムを使用するとMessage、Ideonで表示されるものとは異なりますが、同じように失敗します。


2
@JohnSaunders:OK、この議論をMetaに移すのは良い考えです。これは、この編集に関するメタスタックオーバーフローに投稿したばかりの質問へのリンクです。
フルビオ

27
@casperOne Guys、私の答えをいじるのをやめてください。ポイントは、StreamWriterの代わりにStringWriterを使用することです。それ以外はすべて質問に関係ありません。typeof(T) 対のような詳細について話し合いたい場合は、そのようにしてtoSerialize.GetType()ください。ただし、私の答えではありません。ありがとう。
dtb

9
@dtb申し訳ありませんが、Stack Overflowは共同編集されています。また、この特定の回答はmeta説明されているため、編集は有効です。同意できない場合は、メタのその投稿に返信して、あなたの回答が特別なケースであり、共同で編集すべきではないと思う理由を教えてください。
casperOne 2012年

2
コード的には、これは私が見た中で最も短い例です。+1
froggythefrog 2013

13
StringWriterはIDisposableを実装しているため、usingブロックで囲む必要があります。
TrueWill 2014年

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シリアル化を使用することです(最高の1つは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よりもはるかに優れています。
Herman Van Der Blom 2017年

2
「json online parser」をオンラインで検索すると、json文字列をより人間が読みやすい形式にフォーマットできるオンラインjsonパーサーがいくつか見つかります。
xhafan 2017年

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 2014年

6
ただし、マイナーな変更の1つは、オブジェクトではなくTを返し、返されたオブジェクトをDeserializeObject関数でTにキャストすることです。このようにして、ジェネリックオブジェクトではなく、厳密に型指定されたオブジェクトが返されます。
deadlydog 2014年

@deadlydogに感謝します。修正しました。
ADM-IT

3
TextWriterには、呼び出す必要があるDispose()関数があります。つまり、Usingステートメントを忘れています。
ヘルマンファンデルブロム2017年

38

コード安全メモ

受け入れられた答えについては、のtoSerialize.GetType()代わりに使用することが重要typeof(T)ですXmlSerializerコンストラクタです。最初のコードを使用すると、コードはすべての可能なシナリオをカバーしますが、後者のコードを使用すると失敗することがあります。

これは、このステートメントを動機付けるいくつかのサンプルコードとのリンクです。 XmlSerializer派生型の基本クラスで定義されてtypeof(T)いるを呼び出すメソッドに派生型のインスタンスを渡すため、使用時にExceptionスローして、。http:// ideone .com / 1Z5J1IdeoneはMonoを使用してコードを実行することに注意してください。Microsoft.NETランタイムを使用して取得する実際の例外はIdeoneに表示されるものとは異なるメッセージを持っていますが、同じように失敗します。SerializeObject<T>()

完全を期すために、将来の参照用に完全なコードサンプルをここに投稿します。これは、Ideone(コードを投稿した場所)が将来利用できなくなった場合に備えてです。

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() {}オブジェクトを適切に閉じる/破棄するためにも行う必要があります。
2013年

@Amicableに完全に同意します。私は、オブジェクト型に関するすべての私のポイントを強調するために、コードサンプルをできるだけOPの近くに保つように試みました。とにかく、usingステートメントが私たちにとっても、私たちの愛するIDisposable実装オブジェクトにとっても親友であることを誰かに覚えておくのは良いことです;)
Fulvio

「拡張メソッドを使用すると、新しい派生型を作成したり、再コンパイルしたり、元の型を変更したりせずに、既存の型にメソッドを「追加」できます。」msdn.microsoft.com/en-us/library/bb383977.aspx
エイドリアン

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に設定するとうまくいきました。
Lee Richardson

@LeeRichardsonに感謝-正反対のことをする必要があり、.netの下のXmlWriterもデフォルトでUTF16になっているので、どちらにも書きませんでした。
oPless 2014年

このメモリストリームの組み合わせを使用し、エンコーディングGetStringを介して取得すると、文字列の最初の文字としてプリアンブル/ BOMが含まれます。stackoverflow.com/questions/11701341/…
ジェイミー

@Jamee "Encoding = 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でコードレビューをしたかのように、小さなコメントを追加します。それは物事をきちんと維持するのに役立ち、コードベース内のすべてのオブジェクトと参照されているフレームワークがシリアライズに向いているわけではありません
フランクR.ハウゲン

-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

[C#]

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.