2012-07-03 25 views
5

Tôi đang cố gắng sắp xếp các đối tượng bằng thư viện ServiceStack.Text. Này hoạt độngNối tiếp ExpandoObject với ServiceStack.Tiếp theo

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

tôi nhận được, như tôi mong đợi

{"Value":10,"Product":"Apples"} 

Tuy nhiên

dynamic x = new ExpandoObject(); 
x.Value = 100; 
x.Product = "Apples"; 
Console.WriteLine(JsonSerializer.SerializeToString(x)); 

tôi nhận được trước sự ngạc nhiên của tôi

[{"Key":"Value","Value":100},{"Key":"Product","Value":"Apples"}] 

Tại sao! Chuyện gì vậy?

Thứ hai, làm cách nào tôi có thể nhận được những gì tôi muốn?

+0

Dường như bộ nối tiếp hiểu sai cấu trúc dữ liệu của bạn ... bạn có thể đăng cấu trúc không? –

+0

Nếu bạn cài đặt ServiceStack.Text, bạn sẽ có thể chạy mã của tôi ở trên (lặp lại các câu lệnh sử dụng). –

Trả lời

5

ExpandoObject thực hiện IConnection<KeyValuePair>IEnumerable<KeyValuePair>:

public sealed class ExpandoObject : 
    IDynamicMetaObjectProvider, 
    IDictionary<string, object>, 
    ICollection<KeyValuePair<string, object>>, 
    IEnumerable<KeyValuePair<string, object>>, 
    IEnumerable, INotifyPropertyChanged 

tôi đoán là trong nội bộ, serializer ServiceStack được điều trị các ExpandoObject như một IEnumerable<KeyValuePair>, và vì vậy nó serializes đến một mảng JSON của cặp/giá trị then chốt.


Điều này khác với lần đầu tiên đoạn mã (làm việc) của bạn bởi vì .NET thực sự xây dựng một lớp học thực tế (giấu tên) cho dữ liệu của bạn, về cơ bản nó làm cho:

public class SomeNameTheCompilerMakesUp { 
    internal int Value { get; set; } 
    internal string Product { get; set; } 
} 

cho bạn tự động, vì vậy khi nó được gửi đến serializer, nó đang làm việc với một lớp thực với các thuộc tính thực, trong khi ExpandoObject thực sự được hỗ trợ bởi một object[] nội bộ.


Trên mặt lưu ý, System.Web.Helpers.Json của Microsoft cũng hoạt động tương tự. Xét nghiệm này đi:

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

Một chỉnh sửa cuối cùng:

Bạn có thể làm cho công việc này theo cách bạn muốn bằng cách chuyển ExpandoObject của bạn thành một Dictionary<string, object>. Thông báo trước cho mã này là nó sao chép dữ liệu vào một từ điển, do đó bạn có 2 bản sao trong bộ nhớ (hoặc hơi ít hơn, vì về mặt kỹ thuật các chuỗi có thể được thực hiện).

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

Mặc dù, cho bất cứ ai đi qua sau này, và đang thực sự sử dụng System.Web.Helpers.Json, điều tốt hơn để làm là chỉ cần quấn bạn ExpandoObject trong một DynamicJsonObject như thế này:

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

Ans một lần tôi làm việc thông qua đó, tôi đã tìm thấy một câu hỏi tương tự ở đây: How to flatten an ExpandoObject returned via JsonResult in asp.net mvc?

+0

Cảm ơn Rally, điều này có ý nghĩa. Bất kỳ ý tưởng làm thế nào có thể serialize ExpandoObject theo cách tôi muốn? –

+0

Thật không may, không, tôi không. Tôi đã cố gắng 'System.Web.Helpers.Json' hy vọng rằng nó sẽ làm việc theo cách bạn muốn, và sẽ đề xuất rằng như là một thay thế, nhưng nó làm điều tương tự. :) – CodingWithSpike

+0

@MattHickford - làm xước nhận xét trước của tôi. Tôi đã thêm một giải pháp có thể vào cuối câu trả lời của tôi. – CodingWithSpike

Các vấn đề liên quan