Serializing dictionaries with JavaScriptSerializer

后端 未结 5 690
南旧
南旧 2020-12-03 22:15

Apparently, IDictionary is serialized as an array of KeyValuePair objects (e.g., [{Key:\"foo\", Value:\"bar\"}, ...]

相关标签:
5条回答
  • 2020-12-03 22:18

    I was able to solve with JavaScriptSerializer with Linq Select:

    var dictionary = new Dictionary<int, string>();
    var jsonOutput = new JavaScriptSerializer().Serialize(dictionary.Select(x => new { Id = x.Key, DisplayText = x.Value  }));
    
    0 讨论(0)
  • 2020-12-03 22:19

    No, it is not possible with JavaScriptSerializer. It's possible with Json.NET:

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

    and then:

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

    would produce the desired:

    {"Foos":{"foo":"bar"}}
    
    0 讨论(0)
  • 2020-12-03 22:20

    I was able to solve it using JavaScriptSerializer, the trick is to create your own converter. The following code is working code:

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

    And here's how you use it:

    JavaScriptSerializer js = new JavaScriptSerializer();
    js.RegisterConverters(new JavaScriptConverter[] { new KeyValuePairJsonConverter() });
    Context.Response.Clear();
    Context.Response.ContentType = "application/json";
    Context.Response.Write(js.Serialize(myObject));
    
    0 讨论(0)
  • 2020-12-03 22:33

    Here's an I believe improved version from Tomas answer. Works like a charm. We could also add a check for the ScriptIgnore attribute but well, knock yourself out.

    BTW, I chose JavaScriptSerializer because in my opinion third party solutions are most of the time: less known, long to install, often forgotten pre-requities and have blur copy-right states that make them risky to distribute in business.

    P-S: I didn`t understood why we were trying to deserialize both to the instance and to the instance as a dictionary, so I stripped that part.

    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) });
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-03 22:36

    Although I agree that JavaScriptSerializer is a crap and Json.Net is a better option, there is a way in which you can make JavaScriptSerializer serialize the way you want to. You will have to register a converter and override the Serialize method using something like this:

        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)\/"}
    

    Hope this helps!

    0 讨论(0)
提交回复
热议问题