Сериализация объекта в строку

У меня есть следующий способ сохранения объекта в файл:

// 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 мне как строку (а не сохранить его в файл). Я изучаю это, но пока не понял.

Я думал, что это может быть очень легко для кого-то, знакомого с этими объектами. Если нет, я в конце концов выясню это.

Ответ 1

Используйте 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();
    }
}

Примечание. Важно использовать toSerialize.GetType() вместо typeof(T) в конструкторе XmlSerializer: если вы используете первый код, он охватывает все возможные подклассы T (которые действительны для метода), при использовании последний будет терпеть неудачу при передаче типа, полученного из T. Вот ссылка с некоторым примером кода, который мотивирует этот оператор: XmlSerializer throw , когда используется typeof(T), потому что вы передаете экземпляр производного типа методу, который вызывает SerializeObject, который определен в производном тип базового класса: http://ideone.com/1Z5J1.

Кроме того, Ideone использует Mono для выполнения кода; фактический Exception, который вы получили бы с использованием среды выполнения Microsoft.NET, имеет другой Message, чем тот, который показан на Ideone, но он терпит неудачу точно так же.

Ответ 2

Я знаю, что на самом деле это не ответ на вопрос, но исходя из количества голосов за вопрос и принятого ответа, я подозреваю, что люди фактически используют код для сериализации объекта для строки.

Использование сериализации 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}

Ответ 3

Сериализация и десериализация:

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

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

Ответ 4

Замечание по безопасности кода

Что касается принятого ответа, важно использовать toSerialize.GetType() вместо typeof(T) в конструкторе XmlSerializer: если вы используете первый, который охватывает код все возможные сценарии, в то время как использование последнего иногда случается.

Вот ссылка с некоторым примером кода, который мотивирует этот оператор: XmlSerializer бросает исключение, когда используется typeof(T), потому что вы передаете экземпляр производного типа методу, который вызывает SerializeObject<T>(), который определен в базовом классе производного типа: http://ideone.com/1Z5J1. Обратите внимание, что Ideone использует Mono для выполнения кода: фактическое исключение, которое вы получите с помощью среды выполнения Microsoft.NET, имеет другое сообщение, отличное от того, которое показано на Ideone, но оно не соответствует точно так же.

Для полноты я размещаю полный образец кода здесь для дальнейшего использования, на всякий случай 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();
    }
}

Ответ 5

Мой 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());
                }
            }
        }

Ответ 6

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

Ответ 7

Мне не удалось использовать метод JSONConvert, предложенный xhafan

В .Net 4.5 даже после добавления ссылки на сборку "System.Web.Extensions" мне все еще не удалось получить доступ к JSONConvert.

Однако, как только вы добавите ссылку, вы можете получить такую ​​же распечатку строки, используя:

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

Ответ 8

В некоторых редких случаях вам может понадобиться реализовать собственную сериализацию строк.

Но это, вероятно, идея bad, если вы не знаете, что делаете. (например, сериализация для ввода-вывода с пакетным файлом)

Что-то подобное сделало бы трюк (и его было бы легко отредактировать вручную/партиями), но будьте осторожны, чтобы сделать еще несколько проверок, например, это имя не содержит новую строку.

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