【问题标题】:Serializing dictionaries with JavaScriptSerializer使用 JavaScriptSerializer 序列化字典
【发布时间】:2011-06-20 20:17:02
【问题描述】:

显然,IDictionary<string,object> 被序列化为 KeyValuePair 对象的数组(例如,[{Key:"foo", Value:"bar"}, ...])。是否可以将其序列化为对象(例如,{foo:"bar"})?

【问题讨论】:

  • 是的,不要使用 JavaScriptSerializer,它完全是垃圾。使用 Newtonsoft Json.NET

标签: c# json serialization javascriptserializer


【解决方案1】:

虽然我同意 JavaScriptSerializer 是一个废话,而 Json.Net 是一个更好的选择,但有一种方法可以让 JavaScriptSerializer 按照你想要的方式进行序列化。 您必须注册一个转换器并使用以下方法覆盖 Serialize 方法:

    public class KeyValuePairJsonConverter : JavaScriptConverter
{
    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        var instance = Activator.CreateInstance(type);

        foreach (var p in instance.GetType().GetPublicProperties())
        {
            instance.GetType().GetProperty(p.Name).SetValue(instance, dictionary[p.Name], null);
            dictionary.Remove(p.Name);
        }

        foreach (var item in dictionary)
            (instance).Add(item.Key, item.Value);

        return instance;
    }
    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(your_type) });
        }
    }
}

JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer();
javaScriptSerializer.RegisterConverters(new JavaScriptConverter[] { new ExpandoJsonConverter() });
jsonOfTest = javaScriptSerializer.Serialize(test);
// {"x":"xvalue","y":"\/Date(1314108923000)\/"}

希望这会有所帮助!

【讨论】:

  • 我正在尝试使用您的类,但您的`Class Object` 的instance 变量似乎没有添加方法。
【解决方案2】:

不,JavaScriptSerializer 不可能。 Json.NET 是可能的:

public class Bar
{
    public Bar()
    {
        Foos = new Dictionary<string, string>
        {
            { "foo", "bar" }
        };
    }

    public Dictionary<string, string> Foos { get; set; }
}

然后:

var bar = new Bar();
string json = JsonConvert.SerializeObject(bar, new KeyValuePairConverter());

会产生所需的:

{"Foos":{"foo":"bar"}}

【讨论】:

  • 我一开始是走那条路的。请参阅我之前的问题:stackoverflow.com/questions/6416017/…。我在使用 Json.NET 反序列化嵌套字典时遇到问题。
  • @Daniel,与JavaScriptSerializer 相比,Json.NET 是糖。因此,如果您在使用 Json.NET 时遇到问题,我不知道该说些什么 :-) 就您的其他问题而言,这是完全正常的行为。您向序列化程序指示的只是字符串和对象的字典。因此,您在代码中使用弱类型字典,您期望得到什么回报?当然,你所能得到的只是一个弱类型的 JObjects。使用强类型字典:Dictionary&lt;string, SomeModel&gt;,会有区别。
  • 你指的是什么区别?我没看到。
  • 抱歉,我刚刚看到 DictionaryIDictionary 对比——知道了。谢谢。
【解决方案3】:

我能够使用带有 Linq Select 的 JavaScriptSerializer 解决:

var dictionary = new Dictionary<int, string>();
var jsonOutput = new JavaScriptSerializer().Serialize(dictionary.Select(x => new { Id = x.Key, DisplayText = x.Value  }));

【讨论】:

  • 这在复杂情况下不起作用(即复杂的层次结构),但它确实解决了简单情况下的问题,因此如果您想避免将样板添加到 JavaScriptSerializer 或第三方库。
  • 对我来说,即使在复杂的情况下它也确实有效,只需更改为 .Serialize(dictionary)。它比 JsonConvert 更简单,可以使用。我希望我能给这个答案+2
【解决方案4】:

我能够使用 JavaScriptSerializer 解决它,诀窍是创建自己的转换器。以下代码是工作代码:

public class KeyValuePairJsonConverter : JavaScriptConverter {
    public override object Deserialize(IDictionary<string, object> dictionary
                                        , Type type
                                        , JavaScriptSerializer serializer) {
        throw new InvalidOperationException("Sorry, I do serializations only.");
    }

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer) {
        Dictionary<string, object> result = new Dictionary<string, object>();
        Dictionary<string, MyClass> dictionaryInput = obj as Dictionary<string, MyClass>;

        if (dictionaryInput == null) {
            throw new InvalidOperationException("Object must be of Dictionary<string, MyClass> type.");
        }

        foreach (KeyValuePair<string, MyClass> pair in dictionaryInput)
            result.Add(pair.Key, pair.Value);

        return result;
    }

    public override IEnumerable<Type> SupportedTypes {
        get {
            return new ReadOnlyCollection<Type>(new Type[] { typeof(Dictionary<string, MyClass>) });
        }
    }
}

这是你如何使用它的:

JavaScriptSerializer js = new JavaScriptSerializer();
js.RegisterConverters(new JavaScriptConverter[] { new KeyValuePairJsonConverter() });
Context.Response.Clear();
Context.Response.ContentType = "application/json";
Context.Response.Write(js.Serialize(myObject));

【讨论】:

    【解决方案5】:

    这是我相信 Tomas 答案的改进版本。奇迹般有效。我们也可以添加一个对 ScriptIgnore 属性的检查,但好吧,把自己搞砸了。

    顺便说一句,我选择 JavaScriptSerializer 是因为在我看来,第三方解决方案大部分时间都是:鲜为人知、安装时间长、经常被遗忘的先决条件以及版权状态模糊,这使得它们在业务中分发存在风险。

    P-S:我不明白为什么我们要同时反序列化到实例和作为字典的实例,所以我去掉了那部分。

    public class KeyValuePairJsonConverter : JavaScriptConverter
    {
        public override object Deserialize(IDictionary<string, object> deserializedJSObjectDictionary, Type targetType, JavaScriptSerializer javaScriptSerializer)
        {
            Object targetTypeInstance = Activator.CreateInstance(targetType);
    
            FieldInfo[] targetTypeFields = targetType.GetFields(BindingFlags.Public | BindingFlags.Instance);
    
            foreach (FieldInfo fieldInfo in targetTypeFields)
                fieldInfo.SetValue(targetTypeInstance, deserializedJSObjectDictionary[fieldInfo.Name]);
    
            return targetTypeInstance;
        }
    
        public override IDictionary<string, object> Serialize(Object objectToSerialize, JavaScriptSerializer javaScriptSerializer)
        {
           IDictionary<string, object> serializedObjectDictionary = new Dictionary<string, object>();
    
           FieldInfo[] objectToSerializeTypeFields = objectToSerialize.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
    
           foreach (FieldInfo fieldInfo in objectToSerializeTypeFields)
               serializedObjectDictionary.Add(fieldInfo.Name, fieldInfo.GetValue(objectToSerialize));
    
           return serializedObjectDictionary;
        }
    
        public override IEnumerable<Type> SupportedTypes
        {
            get
            {
                return new ReadOnlyCollection<Type>(new Type[] { typeof(YOURCLASSNAME) });
            }
        }
    }
    

    【讨论】:

    • 关于我的 PS 笔记。也许这是为了允许指定泛型字典类型而不是类型,但老实说,我不明白指定泛型字典类型的意义,因为整个事情都是关于反序列化 字典。而且很繁琐。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-27
    • 1970-01-01
    • 2018-03-03
    • 1970-01-01
    相关资源
    最近更新 更多