使用ServiceStack.Text序列化ExpandoObject

Col*_*nic 5 .net c# json servicestack

我正在尝试使用库ServiceStack.Text序列化对象.这有效

using System.Dynamic;
using ServiceStack.Text;
var x = new {Value= 10, Product = "Apples"};                
Console.WriteLine(JsonSerializer.SerializeToString(x));
Run Code Online (Sandbox Code Playgroud)

我得到了,正如我所料

{"Value":10,"Product":"Apples"}
Run Code Online (Sandbox Code Playgroud)

然而

dynamic x = new ExpandoObject();
x.Value = 100;
x.Product = "Apples";
Console.WriteLine(JsonSerializer.SerializeToString(x));
Run Code Online (Sandbox Code Playgroud)

我很惊讶

[{"Key":"Value","Value":100},{"Key":"Product","Value":"Apples"}]
Run Code Online (Sandbox Code Playgroud)

为什么!这是怎么回事?

其次,我怎样才能得到我想要的东西?

Cod*_*ike 5

ExpandoObject实施IConnection<KeyValuePair>IEnumerable<KeyValuePair>:

public sealed class ExpandoObject :
    IDynamicMetaObjectProvider,
    IDictionary<string, object>,
    ICollection<KeyValuePair<string, object>>,
    IEnumerable<KeyValuePair<string, object>>,
    IEnumerable, INotifyPropertyChanged
Run Code Online (Sandbox Code Playgroud)

我的猜测是,在内部,ServiceStack序列化程序将其ExpandoObject视为一个IEnumerable<KeyValuePair>,因此它序列化为一个键/值对的JSON数组.


这与您的第一个(工作)代码片段不同,因为.NET实际上为您的数据构建了一个真实(匿名)类,基本上它会:

public class SomeNameTheCompilerMakesUp {
    internal int Value { get; set; }
    internal string Product { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

对于你自动,所以当它被发送到序列化程序时,它正在使用具有真实属性的真实类,而ExpandoObject实际上是由object[]内部支持.


另一方面,微软的System.Web.Helpers.Json行为方式相同.该测试通过:

    [TestMethod]
    public void ExpandoObjectSerializesToJsonArray()
    {
        dynamic anonType = new { Value = 10, Product = "Apples" };

        dynamic expando = new ExpandoObject();
        expando.Value = 10;
        expando.Product = "Apples";

        var anonResult = System.Web.Helpers.Json.Encode(anonType);
        var expandoResult = System.Web.Helpers.Json.Encode(expando);

        Assert.AreEqual("{\"Value\":10,\"Product\":\"Apples\"}", anonResult);
        Assert.AreEqual("[{\"Key\":\"Value\",\"Value\":10},{\"Key\":\"Product\",\"Value\":\"Apples\"}]", expandoResult);
    }
Run Code Online (Sandbox Code Playgroud)

最后一次编辑:

你可以把你的工作ExpandoObject变成一个你想要的方式Dictionary<string, object>.对此代码的警告是它将数据复制到字典中,因此您在内存中有2个副本(或者稍微少于,因为从技术上讲,字符串可能被实现).

    [TestMethod]
    public void TestMethod1()
    {
        dynamic expando = new ExpandoObject();
        expando.Value = 10;
        expando.Product = "Apples";

        // copy expando properties to dictionary
        var dictionary = ((ExpandoObject)expando).ToDictionary(x => x.Key, x => x.Value);

        var expandoResult    = System.Web.Helpers.Json.Encode(expando);
        var dictionaryResult = System.Web.Helpers.Json.Encode(dictionary);

        Assert.AreEqual("[{\"Key\":\"Value\",\"Value\":10},{\"Key\":\"Product\",\"Value\":\"Apples\"}]", expandoResult);
        Assert.AreEqual("{\"Value\":10,\"Product\":\"Apples\"}", dictionaryResult);
    }
Run Code Online (Sandbox Code Playgroud)

虽然,对于后来遇到这个并且实际上正在使用的任何人来说System.Web.Helpers.Json,更好的办法就是将你ExpandoObject的内容包装成DynamicJsonObject:

    [TestMethod]
    public void TestMethod1()
    {
        dynamic expando = new ExpandoObject();
        expando.Value = 10;
        expando.Product = "Apples";

        var dictionaryResult = System.Web.Helpers.Json.Encode(new DynamicJsonObject(expando));

        Assert.AreEqual("{\"Value\":10,\"Product\":\"Apples\"}", dictionaryResult);
    }
Run Code Online (Sandbox Code Playgroud)

Ans一旦我完成了这个,我在这里找到了一个类似的问题:如何在asp.net mvc中展平通过JsonResult返回的ExpandoObject?