Сериализация словарей с помощью JavaScriptSerializer - PullRequest
8 голосов
/ 21 июня 2011

Очевидно, IDictionary<string,object> сериализуется как массив KeyValuePair объектов (например, [{Key:"foo", Value:"bar"}, ...]).Возможно ли вместо этого сериализовать его как объект (например, {foo:"bar"})?

Ответы [ 5 ]

11 голосов
/ 31 октября 2012

Хотя я согласен с тем, что 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)\/"}

Надеюсь, это поможет!

4 голосов
/ 21 июня 2011

Нет, это невозможно с 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"}}
3 голосов
/ 14 февраля 2017

Мне удалось решить с помощью JavaScriptSerializer с помощью Linq Select:

var dictionary = new Dictionary<int, string>();
var jsonOutput = new JavaScriptSerializer().Serialize(dictionary.Select(x => new { Id = x.Key, DisplayText = x.Value  }));
1 голос
/ 23 апреля 2014

Вот, кажется, улучшенная версия от ответа Томаса. Работает как шарм. Мы могли бы также добавить проверку атрибута ScriptIgnore, но, тем не менее, вырубить себя.

Кстати, я выбрал JavaScriptSerializer, потому что, по моему мнению, решения сторонних производителей чаще всего бывают: менее известны, долго устанавливаются, часто забывают о предварительных требованиях и имеют размытые состояния авторского права, что делает их рискованными для распространения в бизнесе.

П-С: Я не понял, почему мы пытались десериализовать и экземпляр, и экземпляр как словарь, поэтому я удалил эту часть.

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) });
        }
    }
}
1 голос
/ 21 февраля 2014

Мне удалось решить это с помощью 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));
...