将对象序列化为字符串

Vac*_*ano 294 c# string serialization xml-serialization

我有以下方法将对象保存到文件:

// 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();
}
Run Code Online (Sandbox Code Playgroud)

我承认我没有写它(我只将其转换为带有类型参数的扩展方法).

现在我需要它将xml作为字符串返回给我(而不是将其保存到文件中).我正在研究它,但我还没想到它.

我认为对于熟悉这些对象的人来说这可能很容易.如果不是,我最终会弄明白.

dtb*_*dtb 500

使用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();
    }
}
Run Code Online (Sandbox Code Playgroud)

注意,使用toSerialize.GetType()而不是typeof(T)在XmlSerializer构造函数中使用是很重要的:如果使用第一个代码,代码将涵盖所有可能的子类T(对方法有效),而使用后者则在传递派生类型时会失败T.下面是一些示例代码的链接,它激发了这个语句,XmlSerializer抛出了一个Exceptionwhen typeof(T),因为你将一个派生类型的实例传递给一个方法,该方法调用派生类型的基类中定义的SerializeObject:http:// ideone .com/1Z5J1.

此外,Ideone使用Mono执行代码; Exception使用Microsoft .NET运行时的实际Message情况与Ideone上显示的实际情况有所不同,但它的失败方式却相同.

  • @casperOne伙计们,请停止搞乱我的回答.关键是使用StringWriter而不是StreamWriter,其他一切与问题无关.如果你想讨论诸如`typeof(T)`和`toSerialize.GetType()`之类的细节,请这样做,但不是在我的回答中.谢谢. (24认同)
  • StringWriter实现了IDisposable,因此应该包含在using块中. (12认同)
  • @dtb很抱歉,[Stack Overflow是协同编辑的](http://stackoverflow.com/faq#editing).此外,[这个具体的答案已经在meta讨论](http://meta.stackexchange.com/a/135872/140951),所以编辑代表.如果您不同意,那么请回复关于您认为您的答案是特殊情况的原因的帖子,*不应*进行协作编辑. (8认同)
  • @JohnSaunders:好的,将这个讨论转移到Meta上是一个好主意.这是[我刚刚在关于此编辑的Meta Stack Overflow上发布的问题的链接](http://meta.stackexchange.com/q/135865/188113). (2认同)
  • 在代码方面,这是我所见过的最短的示例。+1 (2认同)

xha*_*fan 69

我知道这不是问题的答案,但根据问题的投票数和接受的答案,我怀疑人们实际上是在使用代码将对象序列化为字符串.

使用XML序列化会在输出中添加不必要的额外文本垃圾.

对于以下课程

public class UserData
{
    public int UserId { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

它会产生

<?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>
Run Code Online (Sandbox Code Playgroud)

更好的解决方案是使用JSON序列化(其中最好的是Json.NET).要序列化对象:

var userData = new UserData {UserId = 0};
var userDataString = JsonConvert.SerializeObject(userData);
Run Code Online (Sandbox Code Playgroud)

要反序列化对象:

var userData = JsonConvert.DeserializeObject<UserData>(userDataString);
Run Code Online (Sandbox Code Playgroud)

序列化的JSON字符串如下所示:

{"UserId":0}
Run Code Online (Sandbox Code Playgroud)

  • @HermanVanDerBlom XML比JSON更具可读性?你在吸烟的世界是什么?这是JSON相对于XML最强大的优势之一:由于更高的信噪比,它更容易阅读.简单地说,使用JSON,内容不会淹没在标签汤中! (9认同)
  • 在这种情况下,你是对的,但是你看过大型XML文档和大型JSON文档.JSON文档几乎无法读取.您正在谈论的名称空间的"垃圾"可以被抑制.生成的XML可以像JSON一样干净,但总是像JSON一样可读.可读性是JSON之上的一大优势. (4认同)
  • 如果你在网上搜索"json online parser",你会发现一些在线json解析器可以用更人性化的方式格式化json字符串. (2认同)

ADM*_*-IT 57

序列化和反序列化:

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

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

  • 与所有其他答案不同,+1也显示如何反序列化.谢谢! (13认同)
  • 但是,一个小的改变是返回T而不是对象,并在DeserializeObject函数中将返回的对象强制转换为T. 这样返回强类型对象而不是通用对象. (6认同)
  • TextWriter有一个应该调用的Dispose()函数.所以你忘记了使用语句. (3认同)

Ful*_*vio 37

代码安全说明

关于接受的答案,重要的是使用toSerialize.GetType()而不是typeof(T)XmlSerializer构造函数中使用:如果使用第一个代码,则代码涵盖所有可能的方案,而使用后者则有时会失败.

这是一个链接,其中包含一些激励此语句的示例代码,XmlSerializertypeof(T)使用时抛出一个Exception ,因为您将派生类型的实例传递给调用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();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 您还应该使用(StringWriter textWriter = new StringWriter(){}`来正确关闭/处理对象. (12认同)

oPl*_*ess 10

我的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());
                }
            }
        }
Run Code Online (Sandbox Code Playgroud)

  • +1 使用 XmlWriterSettings()。我希望我的序列化 XML 不浪费空间与漂亮的打印内容,并设置 Indent = false 和 NewLineOnAttributes = false 完成了这项工作。 (2认同)

tea*_*eng 5

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();
            }
        }
Run Code Online (Sandbox Code Playgroud)