Bir nesneyi dizeye seri hale getirme


311

Bir nesneyi bir dosyaya kaydetmek için aşağıdaki yöntemi var:

// 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();
}

Ben itiraf etmedi itiraf (sadece bir tür parametre aldı bir uzatma yöntemine dönüştürdü).

Şimdi xml (bir dosyaya kaydetmek yerine) bir dize olarak bana geri vermek gerekiyor. Buna bakıyorum, ama henüz çözemedim.

Bunun bu nesnelere aşina biri için gerçekten kolay olabileceğini düşündüm. Değilse sonunda anlayacağım.

Yanıtlar:


530

Şunun StringWriteryerine bir kullanın 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();
    }
}

Not, XmlSerializer yapıcısı toSerialize.GetType()yerine kullanmak önemlidir typeof(T): ilkini kullanırsanız, kod tüm olası alt sınıfları kapsar T(yöntem için geçerli), sonuncuyu kullanırken türetilmiş bir tür iletilirken başarısız olur T. İşte ile bu ifadeyi motive bazı örnek kod ile bir bağlantı XmlSerializerbir atma Exceptionsırasında typeof(T): kullanılır Eğer türetilmiş türünün temel sınıfında tanımlanır SerializeObject çağıran bir yönteme türetilmiş bir türünün bir örneği iletmemizdir, http: // ideone .com / 1Z5J1 .

Ayrıca, Ideone kod yürütmek için Mono kullanır; ExceptionMicrosoft .NET çalışma zamanını kullanarak alacağınız gerçekte MessageIdeone'da gösterilenden farklı , ancak aynı şekilde başarısız oluyor.


2
@JohnSaunders: tamam, bu tartışmayı Meta'ya taşımak iyi bir fikir. İşte bu düzenleme ile ilgili Meta Stack Overflow'da az önce gönderdiğim sorunun bağlantısı .
Fulvio

27
@casperOne Guys, lütfen cevabımı karıştırmayı bırak. Amaç StreamWriter yerine StringWriter kullanmaktır, diğer her şey soru ile ilgili değildir. Aşağıdaki gibi ayrıntıları görüşmek isterseniz typeof(T) karşı toSerialize.GetType(), bunu, ama benim cevap lütfen. Teşekkürler.
dtb

9
@dtb Maalesef Yığın Taşması işbirliği içinde düzenleniyor . Ayrıca, bu özel cevap meta üzerinde tartışılmıştır , bu yüzden düzenleme duruyor. Kabul etmiyorsanız, lütfen cevabınızın neden özel bir durum olduğunu ve birlikte düzenlenmemesi gerektiğini düşündüğünüzle ilgili metadaki bu gönderiyi yanıtlayın .
casperOne

2
Kurallara uygun olarak, bu gördüğüm en kısa örnek. +1
froggythefrog

13
StringWriter IDisposable uygular, bu nedenle bir kullanma bloğu içine alınmalıdır.
TrueWill

70

Bunun gerçekten soruya bir cevap olmadığını biliyorum, ama soru ve kabul edilen cevap için oy sayısına dayanarak, insanların aslında bir dizeye bir nesneyi serileştirmek için kodu kullandığından şüpheleniyorum.

XML serileştirmeyi kullanmak çıktıya gereksiz ekstra metin çöpü ekler.

Aşağıdaki sınıf için

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

üretir

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

Daha iyi bir çözüm JSON serileştirmeyi kullanmaktır (en iyilerinden biri Json.NET ). Bir nesneyi serileştirmek için:

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

Bir nesnenin serisini kaldırmak için:

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

Serileştirilmiş JSON dizesi şöyle görünecektir:

{"UserId":0}

4
Bu durumda haklısınız ancak büyük XML belgeleri ve büyük JSON belgeleri gördünüz mü? JSON belgesi neredeyse okunamıyor. Bahsettiğiniz "çöp" gibi ad alanları bastırılabilir. Oluşturulan XML JSON kadar temiz olabilir, ancak DAİMA JSON kadar daha okunabilir. Okunabilirlik JSON'un üzerinde büyük bir avantajdır.
Herman Van Der Blom

2
"Json online ayrıştırıcı" için çevrimiçi arama yaparsanız, json dizesini daha insan tarafından okunabilir şekilde biçimlendirebilen bazı çevrimiçi json ayrıştırıcıları bulacaksınız.
xhafan

9
@HermanVanDerBlom XML JSON'dan daha okunabilir mi? Dünyada ne içiyorsun? Bu JSON'un XML'e karşı en güçlü avantajlarından biridir: daha yüksek sinyal / gürültü oranı nedeniyle okumak çok daha kolaydır. Basitçe söylemek gerekirse, JSON ile içerik etiket çorbasında boğulmuyor!
Mason Wheeler

63

Serialize ve Deserialize (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
Diğer yanıtların aksine, serileştirmeyi nasıl göstereceğinizi gösteren +1. Teşekkürler!
deadlydog

6
Ancak küçük bir değişiklik, nesne yerine T döndürmek ve döndürülen nesneyi DeserializeObject işlevinde T'ye atamak olacaktır. Bu şekilde, kuvvetle yazılan nesne genel bir nesne yerine döndürülür.
deadlydog

Teşekkürler @deadlydog, tamir ettim.
ADM-IT

3
TextWriter, çağrılması gereken bir Dispose () işlevine sahiptir. Yani Using ifadelerini unutuyorsunuz.
Herman Van Der Blom

38

Kod Güvenliği Notu

Kabul edilen cevapla ilgili olarak yapıcı toSerialize.GetType()yerine kullanmak önemlidir : birincisini kullanırsanız kod tüm olası senaryoları kapsar, ikincisini kullanırken bazen başarısız olur.typeof(T)XmlSerializer

Türetilmiş türün bir örneğini türetilmiş türün temel sınıfında tanımlanan bir yönteme ilettiğiniz için türetilmiş türün bir örneğini kullandığınız XmlSerializeriçin bu ifadeyi motive eden bazı örnek kodlarla bir bağlantı bulunmaktadır : http: // ideone .com / 1Z5J1 . Ideone'nin kodu yürütmek için Mono kullandığını unutmayın: Microsoft .NET çalışma zamanını kullanarak alacağınız istisnanın Ideone'de gösterilen mesajdan farklı bir Mesajı vardır, ancak aynı şekilde başarısız olur.typeof(T)SerializeObject<T>()

Tamlık uğruna, ileride başvurmak üzere tam kod örneğini buraya gönderirim , sadece Ideone (kodu gönderdiğim yer) gelecekte kullanılamaz duruma gelirse:

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
Ayrıca using (StringWriter textWriter = new StringWriter() {}, nesnenin uygun şekilde kapatılması / atılması için de yapmanız gerekir .
Dost canlısı

@Amicable'da sana tamamen katılıyorum! Ben sadece tüm nesne türleri hakkında benim noktaya vurgulamak için, OP bir mümkün olduğunca yakın benim kod örneği tutmaya çalıştım. Her neyse, usingifadenin hem bizim hem de sevgili IDisposableuygulayıcı nesnelerimiz için en iyi arkadaş olduğunu hatırlamak güzel ;)
Fulvio

"Uzantı yöntemleri, yeni bir tür oluşturmadan, yeniden derlemeden veya özgün türü değiştirmeden mevcut türlere" eklemenize "olanak tanır." msdn.microsoft.com/en-us/library/bb383977.aspx
Adrian

12

Benim 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 () kullanmak için +1. Ben serileştirilmiş XML ile güzel yazdırma şeyler ve ayar Indent = yanlış ve NewLineOnAttributes = false ayarını boşa harcamamasını istedim.
Lee Richardson

Teşekkürler @LeeRichardson - Ben de tam tersini yapmak gerekiyordu, ayrıca XmlWriter .net altında UTF16 varsayılan olarak da ne yazıyor ne de değil.
oPless

bellek akışının bu kombinasyonunu kullanmak ve Kodlama GetString yoluyla almak, dizenizdeki ilk karakter olarak Preamble / BOM'yi içerir. Ayrıca bkz. Stackoverflow.com/questions/11701341/…
Jamee

@Jamee "Encoding = UTF8Encoding (false)", BOM'u docs.microsoft.com/en-us/dotnet/api/… ... ' a göre yazmamanız gerektiği anlamına gelir.
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 tarafından önerilen JSONConvert yöntemini kullanamadım

Net 4.5'te bile "System.Web.Extensions" derleme başvurusu ekledikten sonra hala JSONConvert erişemedi.

Ancak, referans ekledikten sonra aynı dizeyi kullanarak çıktısını alabilirsiniz:

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

2
JSONConvert Sınıfı NewtonSoft.Json ad alanındadır. Sen VS içinde paket yöneticisine gidin ve sonra NewtonSoft.Json paketini indirin
Amir Shrestha

1

Bu manipüle edilmiş kodu kabul edilen cevaba paylaşmak zorunda olduğum gibi hissettim - ünüm olmadığı için yorum yapamıyorum ..

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);
            }
        }
    }
}


Bunun eski olduğunu biliyorum, ama gerçekten iyi bir cevap verdiğiniz için, küçük bir yorum ekleyeceğim, sanki bir PR üzerinde bir kod incelemesi yaptım: Jenerik kullanırken T üzerinde kısıtlamalar olmalı. İşleri düzenli tutmaya yardımcı olur ve referans alınan kod tabanındaki ve çerçevelerdeki her nesne serileştirmeye katkıda bulunmaz
Frank R. Haugen

-1

Bazı nadir durumlarda kendi String serileştirmenizi uygulamak isteyebilirsiniz.

Ama ne yaptığınızı bilmiyorsanız , bu muhtemelen kötü bir fikirdir. (örneğin, bir toplu iş dosyasıyla G / Ç için serileştirme)

Böyle bir şey hile yapar (ve elle / toplu olarak düzenlemek kolay olurdu), ancak bu adın yeni satır içermemesi gibi biraz daha fazla kontrol yapılması gerektiğine dikkat edin.

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;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.