5

ライブラリServiceStack.Textを使用してオブジェクトをシリアル化しようとしています。これは機能します

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

私が期待するように、私は得る

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

でも

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

私は驚いた

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

どうして!どうしたの?

第二に、どうすれば欲しいものを手に入れることができますか?

4

1 に答える 1

5

ExpandoObject実装IConnection<KeyValuePair>IEnumerable<KeyValuePair>:

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

私の推測では、ServiceStack シリアライザーは内部的に をExpandoObjectとして扱っているIEnumerable<KeyValuePair>ため、キーと値のペアの JSON 配列にシリアル化されます。


.NET は実際にデータの実際の (匿名) クラスを構築するため、これは最初の (作業中の) コード スニペットとは異なります。

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

そのため、シリアライザーに送信されると、実際のプロパティを持つ実際のクラスで動作しますが、は内部ExpandoObjectで実際にサポートされています。object[]


ちなみに、MicrosoftSystem.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);
    }

最後の編集:

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

ただし、後でこれに遭遇し、実際に を使用している人にとっては、次のようSystem.Web.Helpers.Jsonにラップするだけの方がよいでしょう:ExpandoObjectDynamicJsonObject

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

私がそれを処理した後、ここで同様の質問を見つけました: How to flatten an ExpandoObject returned via JsonResult in asp.net mvc?

于 2012-07-03T14:55:57.133 に答える