如何将C#匿名类型序列化为JSON字符串?

181

我正在尝试使用以下代码将匿名类型序列化为JSON:

var serializer = new DataContractJsonSerializer(thing.GetType());
var ms = new MemoryStream();
serializer.WriteObject(ms, thing);
var json = Encoding.Default.GetString(ms.ToArray()); 

但是,在执行时我遇到了以下异常:

类型'<>f__AnonymousType1`3[System.Int32,System.Int32,System.Object[]]'无法序列化。请考虑使用DataContractAttribute特性对其进行标记,并将您想要序列化的所有成员标记为DataMemberAttribute特性。有关其他支持的类型,请参阅Microsoft .NET Framework文档。

据我所知,无法对匿名类型应用属性。是否有其他方法进行序列化或者我漏掉了什么?

9个回答

162

尝试使用JavaScriptSerializer而不是DataContractJsonSerializer

JavaScriptSerializer serializer = new JavaScriptSerializer();
var output = serializer.Serialize(your_anon_object);

18
看起来在SP1中,Trackback似乎已取消弃用。 - Biswanath
7
这个过时的东西似乎在许多新的微软框架中得到了使用,包括MVC。http://aspnet.codeplex.com/SourceControl/changeset/view/21528#266491 - Nick Berardi
1
我该如何在非ASP.NET项目(控制台应用程序)中包含它? - Alxandr
4
您需要引用 System.Web.Extensions.dll 并添加 using System.Web.Script.Serialization; 语句。 - randomguy
1
一旦执行此操作,输出的类型为字符串... 如何将其作为实际的JSON对象返回,例如在使用"return Json(output);"的MVC4应用程序中? - longda
显示剩余3条评论

93

正如其他人提到的那样,Newtonsoft JSON.NET 是一个不错的选择。这里是一个简单JSON序列化的具体示例:

return JsonConvert.SerializeObject(
    new
    {
       DataElement1,
       SomethingElse
    });
我发现它是一个非常灵活、多功能的库。

18
你可以尝试使用我开发的ServiceStack JsonSerializer。目前它是.NET中最快的JSON序列化器,支持序列化DataContract、任何POCO类型、接口、包括匿名类型在内的迟绑定对象等。 了解详情,还可查看速度测试结果
基本示例:
var customer = new Customer { Name="Joe Bloggs", Age=31 };
var json = customer.ToJson();
var fromJson = json.FromJson<Customer>(); 

注意:仅在性能不重要的情况下使用 Microsoft 的 JavaScriptSerializer,因为我已经将其从基准测试中删除,因为它比其他 JSON 序列化程序慢 40x-100x


8
我正在使用MVC3堆栈上的MS JavaScriptSerializer来序列化少量数据的对象。在这些情况下,它非常快速,只需要不到一毫秒的时间来完成我需要的操作。数据库查询本身需要的时间比这长50倍-100倍,所以在我的情况下它并不是一个显著的瓶颈。 - Brian
2
过早的优化是万恶之源。 - Mathias Lykkegaard Lorenzen
4
“fastest .NET JSON serializer”链接无法访问!此外,这个回答已经超过5年半了。你有没有各种.NET JSON序列化器性能的更新? - ErikE

16

对于那些在2020年左右查看此内容的人:

微软的System.Text.Json命名空间是新宠。就性能而言,就我所知,它是最好的:

var model = new Model
{
    Name = "Test Name",
    Age = 5
};

string json = JsonSerializer.Serialize(model);

正如其他人提到的那样,NewtonSoft.Json库也是一个非常好的库。


12

我找到的最快速的方法是这样的:

var obj = new {Id = thing.Id, Name = thing.Name, Age = 30};
JavaScriptSerializer serializer = new JavaScriptSerializer();
string json = serializer.Serialize(obj);

命名空间:System.Web.Script.Serialization.JavaScriptSerializer


2
而对于反序列化: . . dynamic myObject = JsonConvert.DeserializeObject<dynamic>(output); . . 参考:Newtonsoft.json.dll - i31nGo

11

请注意这是2008年的观点。今天我认为序列化器应该内置,您可以使用swagger +属性来通知消费者有关您的端点和返回数据的信息。


我认为您不应该序列化匿名类型。我知道这里有诱惑;您想快速生成一些即将在松散类型环境(如浏览器中的Javascript)中使用的临时类型。不过,我建议创建一个实际类型并将其标记为可序列化。然后,您可以强制类型化您的Web方法。虽然这对于Javascript毫无影响,但它确实为方法添加了一些自我文档。任何经验丰富的程序员都能够查看函数签名并说,“哦,这是类型Foo!我知道它在JSON中应该是什么样子。”
话虽如此,您可以尝试使用JSON.Net进行序列化。我不知道它是否有效。

3
JSON.Net 目前运行良好。我认为你不应该争论它,因为在许多情况下它都是相当合理的选择。 - aprilchild
2
在看到MVC中使用“throw away”类型后,我可以看到一些令人信服的用途。我认为这是一个非常方便的工具,可以放入你的.Net工具箱中。 - Matthew Whited
13
这是一点我也逐渐变得更加宽容,特别是在消费型场景中。但如果该对象需要返回服务器或在多个位置使用,我仍然认为创建类型会导致问题更少。 - Jason Jackson
DataContract风格的反序列化无法很好地处理多态类型。你必须编写自己的反序列化器。这会导致过多的代码维护。 - micahhoover
一个使用匿名类型进行序列化的用例是针对Web API的单元测试。 - howcheng
另一个用例是,我正在尝试创建一个图表 Web 服务功能,您只需向其发送 JSON 数据和配置结构即可在同一发送中告诉它哪个列是 X 轴,哪个列是 Y 轴...由于我对进入 API 的数据一无所知,因此强类型化是无用的。 - Dan Chase

10

您可以使用Newtonsoft.Json。

var warningJSON = JsonConvert.SerializeObject(new {
               warningMessage = "You have been warned..."
            });

使用微软新库 System.Text.Json 可获得更快的替代方案。

var warningJSON = JsonSerializer.Serialize(new {
               warningMessage = "You have been warned..."
            });

1
假设您将其用于 Web 服务,您只需将以下属性应用于该类即可:
[System.Web.Script.Services.ScriptService]

然后对于每个应该返回 Json 的方法,添加以下属性:

[ScriptMethod(ResponseFormat = ResponseFormat.Json)]

并将方法的返回类型设置为“object”


对于标准的ASP Web服务,方法上不需要添加[ScriptMethod(ResponseFormat = ResponseFormat.Json)],只需使用[WebMethod]即可。 同时,返回类型不应设置为object,而应该是强类型的非复杂类型(即可以序列化的类型)。 - row1

-2
public static class JsonSerializer
{
    public static string Serialize<T>(this T data)
    {
        try
        {
            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
            var stream = new MemoryStream();
            serializer.WriteObject(stream, data);
            string jsonData = Encoding.UTF8.GetString(stream.ToArray(), 0, (int)stream.Length);
            stream.Close();
            return jsonData;
        }
        catch
        {
            return "";
        }
    }
    public static T Deserialize<T>(this string jsonData)
    {
        try
        {
            DataContractJsonSerializer slzr = new DataContractJsonSerializer(typeof(T));
            var stream = new MemoryStream(Encoding.UTF8.GetBytes(jsonData));
            T data = (T)slzr.ReadObject(stream);
            stream.Close();
            return data;
        }
        catch
        {
            return default(T);
        }
    }
}

这不会像问题所述那样序列化匿名类型。 - Mark Sowul

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接