【问题标题】:JavaScriptConverter, ExpandoObject and dynamic typesJavaScriptConverter、ExpandoObject 和动态类型
【发布时间】:2014-03-11 15:28:06
【问题描述】:

我有一个像这样的小测试课:

public class Command
{
    public dynamic MyData { get; set; }
}

作为dynamic MyData,我想使用ExpandoObject,所以我可以这样做:

Command cmd = new Command();
cmd.MyData = new ExpandoObject();
cmd.MyData.SomeStuff = 4;
cmd.MyData.SomeOtherStuff = "hi";

我正在尝试从 json 序列化/反序列化。为此,我使用JavaScriptSerializer
我希望上面的示例对象序列化为:

{
    MyData : {
        SomeStuff : 4,
        SomeOtherStuff : "hi"
    }
}

为此,我需要一个JavaScriptConverter(取自this website):

public class ExpandoJsonConverter : JavaScriptConverter
{
    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        return dictionary.ToExpando();
    }

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        var result = new Dictionary<string, object>();
        var dictionary = obj as IDictionary<string, object>;
        foreach (var item in dictionary)
            result.Add(item.Key, item.Value);
        return result;
    }

    public override IEnumerable<Type> SupportedTypes
    {
        get
        {
            return new ReadOnlyCollection<Type>(new Type[] { typeof(ExpandoObject) });
        }
    }
}

public static class IDictionaryExtensions {
    /// <summary>
    /// Extension method that turns a dictionary of string and object to an ExpandoObject
    /// Snagged from http://theburningmonk.com/2011/05/idictionarystring-object-to-expandoobject-extension-method/
    /// </summary>
    public static ExpandoObject ToExpando(this IDictionary<string, object> dictionary) {
        var expando = new ExpandoObject();
        var expandoDic = (IDictionary<string, object>)expando;

        // go through the items in the dictionary and copy over the key value pairs)
        foreach (var kvp in dictionary) {
            // if the value can also be turned into an ExpandoObject, then do it!
            if (kvp.Value is IDictionary<string, object>) {
                var expandoValue = ((IDictionary<string, object>)kvp.Value).ToExpando();
                expandoDic.Add(kvp.Key, expandoValue);
            }
            else if (kvp.Value is ICollection) {
                // iterate through the collection and convert any strin-object dictionaries
                // along the way into expando objects
                var itemList = new List<object>();
                foreach (var item in (ICollection)kvp.Value) {
                    if (item is IDictionary<string, object>) {
                        var expandoItem = ((IDictionary<string, object>)item).ToExpando();
                        itemList.Add(expandoItem);
                    }
                    else {
                        itemList.Add(item);
                    }
                }

                expandoDic.Add(kvp.Key, itemList);
            }
            else {
                expandoDic.Add(kvp);
            }
        }

        return expando;
    }
}

现在这对序列化很有效,但是反序列化存在以下问题:

  • 因为MyDatadynamic 对象,而ExpandoJsonConverter 需要ExpandoObject,所以反序列化为MyData 的数据属于IDictionary&lt;string, object&gt; 类型。
  • 如果我将dynamic MyData 更改为ExpandoObject MyData,我将无法说出cmd.MyData.SomeStuff = 4;,编译器会告诉我“ExpandoObject 没有名为 SomeStuff 的属性”。
  • 最后,我可以将dynamic 添加到ExpandoJsonConverter 的支持类型列表中,等等,你不能这样做typeof(dynamic)

有人知道一个巧妙的解决方法吗?我真的很喜欢这个功能,但我不能使用像 Newtonsoft 这样的第 3 方序列化库。谢谢。

【问题讨论】:

  • stackoverflow.com/a/5157855 能满足您的要求吗?
  • 感谢您的回复。再次 - 整个主题是关于序列化为 JSON,我已经实现了。我的问题是另一种方式(反序列化 JSON),它给了我字典而不是 ExpandoObject。

标签: c# .net json javascriptserializer expandoobject


【解决方案1】:

反序列化为ExpandoObject,但声明变量dynamic,即你需要的是dynamic d = js.Deserialize&lt;ExpandoObject&gt;(json)

string json = @"{
    MyData : {
        SomeStuff : 4,
        SomeOtherStuff : ""hi""
    }
}";

var js = new JavaScriptSerializer();
js.RegisterConverters(new[] { new ExpandoJsonConverter() });    
dynamic d = js.Deserialize<ExpandoObject>(json);    
Console.WriteLine(d.MyData.SomeOtherStuff);

输出:

如果您需要Command 对象,只需手动构造一个并注入从序列化器返回的dynamic 对象:

var cmd = new Command { MyData = d };
Console.WriteLine(cmd.MyData.SomeStuff);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-02-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    • 2011-06-23
    • 2016-09-17
    • 2014-08-27
    相关资源
    最近更新 更多