Разбор JSON с C # [дубликат]

В первом примере вы просто привязываете эту функцию к событию onclick:

function() {alert(i);};

Это означает, что в событии клика js должен предупредить значение функций i-й строки addlink. Его значение будет 5 из-за цикла for ().

Во втором примере вы создаете функцию, связанную с другой функцией:

function (num) { return function () { alert(num); }; }

Это означает: если вызов со значением, верните мне функцию, которая будет предупреждать входное значение. Например. вызов function(3) вернет function() { alert(3) };.

Вы вызываете эту функцию со значением i на каждой итерации, поэтому вы создаете отдельные функции onclick для каждой ссылки.

Дело в том, что в первом примере ваша функция содержала ссылку на переменную, а во втором - с помощью внешней функции, которую вы заменили ссылкой фактическим значением. Это называется закрытием примерно потому, что вы «закрываете» текущее значение переменной внутри вашей функции, а не сохраняете ссылку на нее.

561
задан richardtallent 30 July 2009 в 19:24
поделиться

19 ответов

Json.NET делает это ...

string json = @"{""key1"":""value1"",""key2"":""value2""}";

var values = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);

Дополнительные примеры: Сериализация коллекций с помощью Json.NET

738
ответ дан Nick Strupat 22 August 2018 в 15:38
поделиться
  • 1
    – Highmastdon 13 June 2012 в 14:56
  • 2
    @Highmastdon Нет, нет. Я нашел лучший способ десериализации в словарь - использовать dynamic как тип значений: JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(json); – Erik Schierboom 16 June 2013 в 10:57
  • 3
    Попробовал несколько ответов на этой странице с очень грязной парой ключ / значение, и JSON.NET был единственным, с которым я пытался это работать. – bnieland 26 March 2014 в 16:24
  • 4
    Не работает, если вы используете массив пар значений ключа в json [{key: "a", value: "1"}, {key: "b", value:"2"}], вы должны сделать что-то вроде этого: var dict = JsonConvert.DeserializeObject<List<KeyValuePair<string, string>>>(json); – Adrian 6 May 2016 в 19:44
  • 5
    Также не работает, если значения представляют собой вложенные объекты, поскольку json.net создает их как JObjects – Kugel 13 September 2016 в 13:13

Кажется, все эти ответы здесь предполагают, что вы можете получить эту маленькую строку из более крупного объекта ... для людей, которые хотят просто обезвреживать большой объект с помощью такого словаря где-то внутри сопоставления и кто использует System.Runtime.Serialization.Json DataContract system, вот решение:

Ответ на gis.stackexchange.com имел эту интересную ссылку . Мне пришлось восстановить его с archive.org, но он предлагает довольно совершенное решение: пользовательский класс IDataContractSurrogate, в котором вы реализуете именно ваши собственные типы. Я смог легко расширить его.

Я сделал кучу изменений в нем. Поскольку исходный исходный код больше не доступен, я буду публиковать весь класс здесь:

using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;

namespace JsonTools
{
    /// <summary>
    /// Allows using Dictionary&lt;String,String&gt; and Dictionary&lt;String,Boolean&gt; types, and any others you'd like to add.
    /// Source: https://web.archive.org/web/20100317222656/my6solutions.com/post/2009/06/30/DataContractSerializer-DataContractJsonSerializer-JavaScriptSerializer-XmlSerializer-for-serialization.aspx
    /// </summary>
    public class JsonSurrogate : IDataContractSurrogate
    {
        /// <summary>
        /// Deserialize an object with added support for the types defined in this class.
        /// </summary>
        /// <typeparam name="T">Contract class</typeparam>
        /// <param name="json">JSON String</param>
        /// <param name="encoding">Text encoding</param>
        /// <returns>The deserialized object of type T</returns>
        public static T Deserialize<T>(String json, Encoding encoding)
        {
            if (encoding == null)
                encoding = new UTF8Encoding(false);
            DataContractJsonSerializer deserializer = new DataContractJsonSerializer(
                typeof(T), new Type[0], int.MaxValue, true, new JsonSurrogate(), false);
            using (MemoryStream stream = new MemoryStream(encoding.GetBytes(json)))
            {
                T result = (T)deserializer.ReadObject(stream);
                return result;
            }
        }

        // make sure all values in this are classes implementing JsonSurrogateObject.
        private static Dictionary<Type, Type> KnownTypes = 
            new Dictionary<Type, Type>()
            {
                {typeof(Dictionary<String, String>), typeof(SSDictionary)},
                {typeof(Dictionary<String, Boolean>), typeof(SBDictionary)}
            };

        #region Implemented surrogate dictionary classes

        [Serializable]
        public class SSDictionary : SurrogateDictionary<String>
        {
            public SSDictionary() : base() {}
            protected SSDictionary (SerializationInfo info, StreamingContext context) : base(info, context) {}
        }
        [Serializable]
        public class SBDictionary : SurrogateDictionary<Boolean>
        {
            public SBDictionary() : base() {}
            protected SBDictionary (SerializationInfo info, StreamingContext context) : base(info, context) {}
        }

        #endregion

        /// <summary>Small interface to easily extract the final value from the object.</summary>
        public interface JsonSurrogateObject
        {
            Object DeserializedObject { get; }
        }

        /// <summary>
        /// Class for deserializing any simple dictionary types with a string as key.
        /// </summary>
        /// <typeparam name="T">Any simple type that will be deserialized correctly.</typeparam>
            [Serializable]
        public abstract class SurrogateDictionary<T> : ISerializable, JsonSurrogateObject
        {
            public Object DeserializedObject { get { return dict; } }
            private Dictionary<String, T> dict;

            public SurrogateDictionary()
            {
                dict = new Dictionary<String, T>();
            }

            // deserialize
            protected SurrogateDictionary(SerializationInfo info, StreamingContext context)
            {
                dict = new Dictionary<String, T>();
                foreach (SerializationEntry entry in info)
                {
                    // This cast will only work for base types, of course.
                    dict.Add(entry.Name, (T)entry.Value);
                }
            }
            // serialize
            public void GetObjectData(SerializationInfo info, StreamingContext context)
            {
                foreach (String key in dict.Keys)
                {
                    info.AddValue(key, dict[key]);
                }
            }

        }

        /// <summary>
            /// Uses the KnownTypes dictionary to get the surrogate classes.
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public Type GetDataContractType(Type type)
        {
            Type returnType;
            if (KnownTypes.TryGetValue(type, out returnType))
            {
                return returnType;
            }
            return type;
        }

        public object GetObjectToSerialize(object obj, Type targetType)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        ///     Gets the object out of the surrogate datacontract object. This function is the reason all surrogate objects need to implement the JsonSurrogateObject class.
        /// </summary>
        /// <param name="obj">Result of the deserialization</param>
        /// <param name="targetType">Expected target type of the deserialization</param>
        /// <returns></returns>
        public object GetDeserializedObject(object obj, Type targetType)
        {
            if (obj is JsonSurrogateObject)
            {
                return ((JsonSurrogateObject)obj).DeserializedObject;
            }
            return obj;
        }

        public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
        {
            return null;
        }

        #region not implemented

        public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType)
        {
            throw new NotImplementedException();
        }

        public object GetCustomDataToExport(Type clrType, Type dataContractType)
        {
            throw new NotImplementedException();
        }

        public void GetKnownCustomDataTypes(Collection<Type> customDataTypes)
        {
            throw new NotImplementedException();
        }

        public CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit)
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}

Чтобы добавить новые поддерживаемые типы в класс, вам просто нужно добавить свой класс, дать ему правильные конструкторы и функции (посмотрите на SurrogateDictionary для примера), убедитесь, что он наследует JsonSurrogateObject и добавляет его сопоставление типов в словарь KnownTypes. Включенный SurrogateDictionary может служить основой для любых типов Dictionary<String,T>, где T - любой тип, который десериализуется правильно.

Вызов очень простой:

MyObjtype newObj = JsonSurrogate.Deserialize<MyObjtype>(jsonStr, encoding);

Обратите внимание, что для некоторых причина в том, что эта вещь имеет проблемы с использованием ключевых строк, содержащих пробелы; они просто не присутствовали в финальном списке. Может быть, это просто против json specs, и api, который я звонил, был плохо реализован, заметьте; Не знаю. Во всяком случае, я решил это путем регулярного выражения, заменив их символами подчеркивания в исходных данных json и установив словарь после десериализации.

2
ответ дан Community 22 August 2018 в 15:38
поделиться

У меня была такая же проблема, поэтому я написал это сам. Это решение отличается от других ответов, поскольку оно может десериализоваться на нескольких уровнях.

Просто отправьте строку JSON в функцию deserializeToDictionary , она вернет не строго типизированный объект Dictionary<string, object> .

Старый код

private Dictionary<string, object> deserializeToDictionary(string jo)
{
    var values = JsonConvert.DeserializeObject<Dictionary<string, object>>(jo);
    var values2 = new Dictionary<string, object>();
    foreach (KeyValuePair<string, object> d in values)
    {
        // if (d.Value.GetType().FullName.Contains("Newtonsoft.Json.Linq.JObject"))
        if (d.Value is JObject)
        {
            values2.Add(d.Key, deserializeToDictionary(d.Value.ToString()));
        }
        else
        {
            values2.Add(d.Key, d.Value);
        }
    }
    return values2;
}

Пример: Это вернет объект Dictionary<string, object> ответа JSON в Facebook.

Тест

private void button1_Click(object sender, EventArgs e)
{
    string responsestring = "{\"id\":\"721055828\",\"name\":\"Dasun Sameera Weerasinghe\",\"first_name\":\"Dasun\",\"middle_name\":\"Sameera\",\"last_name\":\"Weerasinghe\",\"username\":\"dasun\",\"gender\":\"male\",\"locale\":\"en_US\",  hometown: {id: \"108388329191258\", name: \"Moratuwa, Sri Lanka\",}}";
    Dictionary<string, object> values = deserializeToDictionary(responsestring);
}

Примечание: родной город далее deserilize в объект Dictionary<string, object>.

Update

Мой старый ответ отлично работает, если в строке JSON нет массива. Это еще один deserialize в List<object>, если элемент является массивом.

Просто отправьте строку JSON в функцию deserializeToDictionaryOrList , она вернет не строго типизированную Dictionary<string, object> или List<object> .

private static object deserializeToDictionaryOrList(string jo,bool isArray=false)
{
    if (!isArray)
    {
        isArray = jo.Substring(0, 1) == "[";
    }
    if (!isArray)
    {
        var values = JsonConvert.DeserializeObject<Dictionary<string, object>>(jo);
        var values2 = new Dictionary<string, object>();
        foreach (KeyValuePair<string, object> d in values)
        {
            if (d.Value is JObject)
            {
                values2.Add(d.Key, deserializeToDictionary(d.Value.ToString()));
            }
            else if (d.Value is JArray)
            {
                values2.Add(d.Key, deserializeToDictionary(d.Value.ToString(), true));
            }
            else
            {
                values2.Add(d.Key, d.Value);
            }
        }
        return values2;
    }else
    {
        var values = JsonConvert.DeserializeObject<List<object>>(jo);
        var values2 = new List<object>();
        foreach (var d in values)
        {
            if (d is JObject)
            {
                values2.Add(deserializeToDictionary(d.ToString()));
            }
            else if (d is JArray)
            {
                values2.Add(deserializeToDictionary(d.ToString(), true));
            }
            else
            {
                values2.Add(d);
            }
        }
        return values2;
    }
}
28
ответ дан Dasun 22 August 2018 в 15:38
поделиться
  • 1
  • 2
    Не проблема. Я только упоминаю об этом, потому что изучение операторов is и as очень помогло мне и упростило мой собственный код. – Jordan 5 March 2015 в 17:48
  • 3
    Он работает, но не эффективен, потому что он вызывает ToString, а затем Deserialize снова. Посмотрите на ответ Фалько ниже. Он десериализует исходную строку только один раз. – Sergei Zinovyev 9 January 2017 в 18:52
  • 4

Если вы после легкого, не-добавленного-ссылочного типа подхода, может быть, этот бит кода, который я только что написал, будет работать (я не могу гарантировать надежность на 100%).

using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

public Dictionary<string, object> ParseJSON(string json)
{
    int end;
    return ParseJSON(json, 0, out end);
}
private Dictionary<string, object> ParseJSON(string json, int start, out int end)
{
    Dictionary<string, object> dict = new Dictionary<string, object>();
    bool escbegin = false;
    bool escend = false;
    bool inquotes = false;
    string key = null;
    int cend;
    StringBuilder sb = new StringBuilder();
    Dictionary<string, object> child = null;
    List<object> arraylist = null;
    Regex regex = new Regex(@"\\u([0-9a-z]{4})", RegexOptions.IgnoreCase);
    int autoKey = 0;
    for (int i = start; i < json.Length; i++)
    {
        char c = json[i];
        if (c == '\\') escbegin = !escbegin;
        if (!escbegin)
        {
            if (c == '"')
            {
                inquotes = !inquotes;
                if (!inquotes && arraylist != null)
                {
                    arraylist.Add(DecodeString(regex, sb.ToString()));
                    sb.Length = 0;
                }
                continue;
            }
            if (!inquotes)
            {
                switch (c)
                {
                    case '{':
                        if (i != start)
                        {
                            child = ParseJSON(json, i, out cend);
                            if (arraylist != null) arraylist.Add(child);
                            else
                            {
                                dict.Add(key, child);
                                key = null;
                            }
                            i = cend;
                        }
                        continue;
                    case '}':
                        end = i;
                        if (key != null)
                        {
                            if (arraylist != null) dict.Add(key, arraylist);
                            else dict.Add(key, DecodeString(regex, sb.ToString()));
                        }
                        return dict;
                    case '[':
                        arraylist = new List<object>();
                        continue;
                    case ']':
                        if (key == null)
                        {
                            key = "array" + autoKey.ToString();
                            autoKey++;
                        }
                        if (arraylist != null && sb.Length > 0)
                        {
                            arraylist.Add(sb.ToString());
                            sb.Length = 0;
                        }
                        dict.Add(key, arraylist);
                        arraylist = null;
                        key = null;
                        continue;
                    case ',':
                        if (arraylist == null && key != null)
                        {
                            dict.Add(key, DecodeString(regex, sb.ToString()));
                            key = null;
                            sb.Length = 0;
                        }
                        if (arraylist != null && sb.Length > 0)
                        {
                            arraylist.Add(sb.ToString());
                            sb.Length = 0;
                        }
                       continue;
                    case ':':
                        key = DecodeString(regex, sb.ToString());
                        sb.Length = 0;
                        continue;
                }
            }
        }
        sb.Append(c);
        if (escend) escbegin = false;
        if (escbegin) escend = true;
        else escend = false;
    }
    end = json.Length - 1;
    return dict; //theoretically shouldn't ever get here
}
private string DecodeString(Regex regex, string str)
{
    return Regex.Unescape(regex.Replace(str, match => char.ConvertFromUtf32(Int32.Parse(match.Groups[1].Value, System.Globalization.NumberStyles.HexNumber))));
}

[Я понимаю, что это нарушает OP Limitation # 1, но технически вы этого не пишете, я сделал]

16
ответ дан dexy 22 August 2018 в 15:38
поделиться
  • 1
    Это единственный ответ для Silverlight и без зависимости! Silverlight не имеет JavascriptSerializer или Serializable. И никакая зависимость не означает Json.NET, RestSharp или MiniJSON. Только @DanCsharpster попробовал другое возможное решение, но, к сожалению, он не работал для меня, как этот. – Cœur 28 August 2014 в 11:24
  • 2
    Что не так с добавлением ссылки на что-то простое, как JSON.NET? Нужно ли быть таким легким, что вы ничего не можете сослаться? Я не говорю, что ваш код не будет работать, но в любое время, когда вы сворачиваете свои собственные, вы, очевидно, рискуете, что ваш код не будет таким же надежным, как в случае с красными случаями, или быстро, как проверенная библиотека, такая как JSON.NET. – Dan Csharpster 28 August 2014 в 17:32
  • 3
    Роллинг - это плохая идея, когда у вас есть хорошая альтернатива. Я не знаю, какая ситуация должна быть , что легко. И я предпочел бы иметь менее оптимальный код, который легко читать и изменять. – Jordan 3 March 2015 в 17:27
  • 4
    Я изначально написал этот фрагмент кода, потому что у меня не было альтернативы. Учитывайте такие вещи, как Silverlight или поставщики различных типов для продуктов Office, где добавление внешних ссылок на проект является либо чрезвычайно проблематичным, либо невозможным. – dexy 10 April 2015 в 12:58
  • 5
    Я знаю его несколько лет спустя, но это все еще очень важный вопрос. Для кого-то интересно, почему мы хотим идти так легко, хорошо, если вы работаете с SQL CLR C #, существует только так много «безопасных». библиотеки, которые вы можете использовать, и System.RunTime.Serialization не является одним из них, к сожалению, JSON.NET зависит от него и, следовательно, он не может быть использован. Спасибо dexy за вашу отличную работу, я посмел немного улучшить ее, чтобы иметь возможность десериализовать массивы массивов, увидеть обновленный код в моем ответе здесь . – Alberto Rechy 23 May 2018 в 16:15

Мне просто нужно было проанализировать вложенный словарь, например

{
    "x": {
        "a": 1,
        "b": 2,
        "c": 3
    }
}

, где JsonConvert.DeserializeObject не помогает. Я нашел следующий подход:

var dict = JObject.Parse(json).SelectToken("x").ToObject<Dictionary<string, int>>();

SelectToken позволяет вам копать до нужного поля. Вы даже можете указать путь, подобный "x.y.z", чтобы перейти дальше в объект JSON.

9
ответ дан Falko 22 August 2018 в 15:38
поделиться
  • 1
    JObject.Parse (json) .ToObject & lt; Dictionary & lt; Guid, List & lt; int & gt; & gt; () работал для меня в моем сценарии благодаря – geedubb 30 August 2016 в 20:30

На основании комментариев выше try JsonConvert.DeserializeObject<Dictionary<string,dynamic>>(json)

var json = @"{""key1"":1,""key2"":""value2"", ""object1"":{""property1"":""value1"",""property2"":[2,3,4,5,6,7]}}";
var parsedObject = JsonConvert.DeserializeObject<Dictionary<string,dynamic>>(json);

, похоже, работает даже для сложных объектов и списков.

2
ответ дан FistOfFury 22 August 2018 в 15:38
поделиться

Довольно раздражающе, если вы хотите использовать привязки модели по умолчанию, похоже, вам придется использовать числовые значения индекса, такие как форма POST.

См. следующий отрывок из этой статьи http : //msdn.microsoft.com/en-us/magazine/hh781022.aspx :

Хотя это несколько противоречиво, запросы JSON имеют одинаковые требования - они тоже должны придерживаться синтаксиса присваивания формы post. Возьмем, например, полезную нагрузку JSON для предыдущей коллекции UnitPrice. Чистый синтаксис массива JSON для этих данных будет представлен как:

[ 
  { "Code": "USD", "Amount": 100.00 },
  { "Code": "EUR", "Amount": 73.64 }
]

Однако поставщикам значений по умолчанию и привязкам к модели требуется, чтобы данные были представлены в виде сообщения формы JSON:

{
  "UnitPrice[0].Code": "USD",
  "UnitPrice[0].Amount": 100.00,

  "UnitPrice[1].Code": "EUR",
  "UnitPrice[1].Amount": 73.64
}

Сценарий создания сложных объектов - это, пожалуй, один из наиболее проблемных сценариев, с которыми сталкиваются разработчики, потому что синтаксис не обязательно очевиден для всех разработчиков. Однако, как только вы узнаете относительно простой синтаксис для публикации сложных коллекций, эти сценарии становятся намного легче иметь дело.

0
ответ дан jeremysawesome 22 August 2018 в 15:38
поделиться

Я добавил код, представленный jSnake04 и Dasun. Я добавил код для создания списков объектов из экземпляров JArray. Он имеет двухстороннюю рекурсию, но поскольку он функционирует на фиксированной конечной модели дерева, нет риска переполнения стека, если данные не массивны.

/// <summary>
/// Deserialize the given JSON string data (<paramref name="data"/>) into a
///   dictionary.
/// </summary>
/// <param name="data">JSON string.</param>
/// <returns>Deserialized dictionary.</returns>
private IDictionary<string, object> DeserializeData(string data)
{
    var values = JsonConvert.DeserializeObject<Dictionary<string, object>>(data);

    return DeserializeData(values);
}

/// <summary>
/// Deserialize the given JSON object (<paramref name="data"/>) into a dictionary.
/// </summary>
/// <param name="data">JSON object.</param>
/// <returns>Deserialized dictionary.</returns>
private IDictionary<string, object> DeserializeData(JObject data)
{
    var dict = data.ToObject<Dictionary<String, Object>>();

    return DeserializeData(dict);
}

/// <summary>
/// Deserialize any elements of the given data dictionary (<paramref name="data"/>) 
///   that are JSON object or JSON arrays into dictionaries or lists respectively.
/// </summary>
/// <param name="data">Data dictionary.</param>
/// <returns>Deserialized dictionary.</returns>
private IDictionary<string, object> DeserializeData(IDictionary<string, object> data)
{
    foreach (var key in data.Keys.ToArray()) 
    {
        var value = data[key];

        if (value is JObject)
            data[key] = DeserializeData(value as JObject);

        if (value is JArray)
            data[key] = DeserializeData(value as JArray);
    }

    return data;
}

/// <summary>
/// Deserialize the given JSON array (<paramref name="data"/>) into a list.
/// </summary>
/// <param name="data">Data dictionary.</param>
/// <returns>Deserialized list.</returns>
private IList<Object> DeserializeData(JArray data)
{
    var list = data.ToObject<List<Object>>();

    for (int i = 0; i < list.Count; i++)
    {
        var value = list[i];

        if (value is JObject)
            list[i] = DeserializeData(value as JObject);

        if (value is JArray)
            list[i] = DeserializeData(value as JArray);
    }

    return list;
}
3
ответ дан Jordan 22 August 2018 в 15:38
поделиться

Для тех, кто ищет в Интернете и наткнулся на этот пост, я написал сообщение в блоге о том, как использовать класс JavaScriptSerializer.

Подробнее ... http://procbits.com/ 2011/04/21 / quick-json-serializationdeserialization-in-c /

Вот пример:

var json = "{\"id\":\"13\", \"value\": true}";
var jss = new JavaScriptSerializer();
var table = jss.Deserialize<dynamic>(json);
Console.WriteLine(table["id"]);
Console.WriteLine(table["value"]);
50
ответ дан JP Richardson 22 August 2018 в 15:38
поделиться
  • 1
    hm, я пробовал ваше решение ... У меня есть json, как этот {& quot; id & quot;: & quot ;, & quot ;, & quot; значение & quot ;: true}, и для меня только словарь & lt; dynamic & gt; решения – Marko 10 May 2011 в 15:35
  • 2
    ok Я нашел его где проблема ... вам нужно добавить [] после объявления словаря, чтобы десериализовать правильно ... Я добавляю комментарий к вашему сообщению в блоге тоже ... ура;) – Marko 10 May 2011 в 15:50
  • 3
    Я обновил свой ответ, чтобы отразить ваш конкретный набор данных. Он отлично работает с динамикой. – JP Richardson 11 May 2011 в 15:28
  • 4
    Я просто написал другой парсер JSON, который немного более гибкий и поддерживает Silverlight: procbits.com/2011/08/11/… – JP Richardson 11 August 2011 в 20:49

Марк Рендл опубликовал это в качестве комментария , я хотел опубликовать его в качестве ответа, поскольку это единственное решение, которое до сих пор работало, чтобы вернуть успех, а коды ошибок json из Google reCaptcha.

string jsonReponseString= wClient.DownloadString(requestUrl);    
IDictionary<string, object> dict = new JavaScriptSerializer().DeserializeObject(jsonReponseString) as IDictionary<string, object>;

Еще раз спасибо, Марк!

3
ответ дан jpaugh 22 August 2018 в 15:38
поделиться

Я обнаружил, что .NET имеет встроенный способ передачи строки JSON в Dictionary<String, Object> через тип System.Web.Script.Serialization.JavaScriptSerializer в сборке 3.5 System.Web.Extensions. Используйте метод DeserializeObject(String).

Я наткнулся на это, сделав сообщение ajax (через jquery) типа контента «application / json» на статический метод .NET-страницы и увидел, что метод (который имел единственный параметр типа Object), магически получивший этот Словарь.

93
ответ дан kbrimington 22 August 2018 в 15:38
поделиться
  • 1
    но встроенный javascriptserializer более груб чем json.net, это решение лучше. Например, javascriptseralizer вернет нули вместо пустых строк и вообще не работает для свойств с нулевым значением и т. Д. – pilavdzice 23 April 2012 в 23:12
  • 2
    @pilavdzice Не говоря уже о том, какое удовольствие вы испытываете при попытке синтаксического анализа, поскольку он предполагает нестандартный формат даты MS. – Basic 21 June 2012 в 15:21
  • 3
    Пример быстрого кода: var jsSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();, а затем Dictionary<string, object> dict = (Dictionary<string, object>)jsSerializer.DeserializeObject(jsonString); – Nate Cook 18 June 2013 в 21:04
  • 4
    Преимущество примера Nate Cook в простом случае - избежать необходимости использования внешних DLL. Я получаю доступ к API с автономной консоли, которая может полагаться только на инфраструктуру .Net. – Nick.T 20 May 2016 в 08:59

Немного поздно в игре, но не вышеперечисленные решения указали мне в сторону чистого и простого решения .NET, а не json.net. Итак, вот оно, оказалось очень простым. Ниже приведен полный пример того, как это делается при стандартной сериализации .NET Json, в примере есть словарь как в корневом объекте, так и в дочерних объектах.

Золотая пуля - это кот, проанализируйте настройки как второй параметр для сериализатора:

DataContractJsonSerializerSettings settings =
                       new DataContractJsonSerializerSettings();
                    settings.UseSimpleDictionaryFormat = true;

Полный код ниже:

using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;

    namespace Kipon.dk
    {
        public class JsonTest
        {
            public const string EXAMPLE = @"{
                ""id"": ""some id"",
                ""children"": {
                ""f1"": {
                    ""name"": ""name 1"",
                    ""subs"": {
                    ""1"": { ""name"": ""first sub"" },
                    ""2"": { ""name"": ""second sub"" }
                    }
                },
                ""f2"": {
                    ""name"": ""name 2"",
                    ""subs"": {
                    ""37"": { ""name"":  ""is 37 in key""}
                    }
                }
                }
            }
            ";

            [DataContract]
            public class Root
            {
                [DataMember(Name ="id")]
                public string Id { get; set; }

                [DataMember(Name = "children")]
                public Dictionary<string,Child> Children { get; set; }
            }

            [DataContract]
            public class Child
            {
                [DataMember(Name = "name")]
                public string Name { get; set; }

                [DataMember(Name = "subs")]
                public Dictionary<int, Sub> Subs { get; set; }
            }

            [DataContract]
            public class Sub
            {
                [DataMember(Name = "name")]
                public string Name { get; set; }
            }

            public static void Test()
            {
                var array = System.Text.Encoding.UTF8.GetBytes(EXAMPLE);
                using (var mem = new System.IO.MemoryStream(array))
                {
                    mem.Seek(0, System.IO.SeekOrigin.Begin);
                    DataContractJsonSerializerSettings settings =
                       new DataContractJsonSerializerSettings();
                    settings.UseSimpleDictionaryFormat = true;

                    var ser = new DataContractJsonSerializer(typeof(Root), settings);
                    var data = (Root)ser.ReadObject(mem);
                    Console.WriteLine(data.Id);
                    foreach (var childKey in data.Children.Keys)
                    {
                        var child = data.Children[childKey];
                        Console.WriteLine(" Child: " + childKey + " " + child.Name);
                        foreach (var subKey in child.Subs.Keys)
                        {
                            var sub = child.Subs[subKey];
                            Console.WriteLine("   Sub: " + subKey + " " + sub.Name);
                        }
                    }
                }
            }
        }
    }
0
ответ дан Kjeld Poulsen 22 August 2018 в 15:38
поделиться

Пытался не использовать какую-либо внешнюю реализацию JSON, поэтому я deserialised следующим образом:

string json = "{\"id\":\"13\", \"value\": true}";

var serializer = new JavaScriptSerializer(); //using System.Web.Script.Serialization;

Dictionary<string, string> values = serializer.Deserialize<Dictionary<string, string>>(json);
38
ответ дан musefan 22 August 2018 в 15:38
поделиться
  • 1
    Добавьте ссылку System.Web.Extensions для использования System.Web.Script – Patrick Cullen 22 February 2012 в 22:07
  • 2
    Мне нравится этот ответ лучше всего, потому что он прост и использует .NET System.Web.Script.Serialization. Это просто работает. Я даже мог использовать "invalid" JSON нравится string json = "{'id':13, 'value': true}";. – styfle 27 December 2012 в 01:04
  • 3
    Из любопытства существует ли один и тот же один способ десериализации в словарь OrdinalIgnoreCase? – batbaatar 12 November 2014 в 00:36

Я только что реализовал это в RestSharp . Это сообщение было полезно для меня.

Кроме кода в ссылке, вот мой код. Теперь я получаю Dictionary результатов, когда я делаю что-то вроде этого:

var jsonClient = new RestClient(url.Host);
jsonClient.AddHandler("application/json", new DynamicJsonDeserializer());
var jsonRequest = new RestRequest(url.Query, Method.GET);
Dictionary<string, dynamic> response = jsonClient.Execute<JObject>(jsonRequest).Data.ToObject<Dictionary<string, dynamic>>();

Помните о том, какой JSON вы ожидаете - в моем случае я возвращал один объект с несколькими свойства. В прикрепленной ссылке автор извлекал список.

1
ответ дан northben 22 August 2018 в 15:38
поделиться

Я бы предложил использовать System.Runtime.Serialization.Json, который является частью .NET 4.5.

[DataContract]
public class Foo
{
   [DataMember(Name = "data")]
   public Dictionary<string,string> Data { get; set; }
}

Затем используйте его следующим образом:

var serializer = new DataContractJsonSerializer(typeof(List<Foo>));
var jsonParams = @"{""data"": [{""Key"":""foo"",""Value"":""bar""}] }";
var stream = new MemoryStream(Encoding.UTF8.GetBytes(jsonParams));

var obj = serializer.ReadObject(stream);
Console.WriteLine(obj);
0
ответ дан nyedidikeke 22 August 2018 в 15:38
поделиться
  • 1
    Где определяется сериализатор? – bnieland 26 March 2014 в 16:16
  • 2
    @bnieland, см. обновленный код выше. – Dan Csharpster 26 March 2014 в 20:25
  • 3
    Это всего лишь модельный класс, который я сериализую для своего проекта. Предполагается, что это класс Foo, но я переписал весь раздел из производственного кода. Вы должны создать свой собственный, как мой класс Foo. Я переименовал его в Foo, чтобы сделать его проще. Это просто класс свойств или полей, которые вы хотите сериализовать для json и обратно. – Dan Csharpster 27 March 2014 в 05:11
  • 4
    @DanCsharpster С точным копированием вашего кода я получаю на Windows Phone 8.1 Silverlight: «Исключение типа« System.Security.SecurityException »произошло в System.ServiceModel.Web.ni.dll, но не было обработано пользователем код Дополнительная информация: Тип контракта данных «MyApp.Foo» не может быть десериализован, поскольку элемент «Данные» не является общедоступным. Публикация этого элемента будет исправлена. Кроме того, вы можете сделать его внутренним и использовать атрибут InternalsVisibleToAttribute на своей сборке, чтобы разрешить сериализацию внутренних элементов – Cœur 28 August 2014 в 09:45
  • 5
    @DanCsharpster И при изменении свойства Data, чтобы быть членом (без get; set;), я получаю: В System.ServiceModel.Web.ni.dll появилось исключение первого исключения типа «System.ArgumentException». Дополнительная информация: Объект type 'System.Object' не может быть преобразован в тип 'System.Collections.Generic.Dictionary`2 [System.String, System.String]'. – Cœur 28 August 2014 в 09:51

Мой подход напрямую десериализуется в IDictionary, без JObject или ExpandObject между ними. В коде используется конвертер, который в основном копируется из класса ExpandoObjectConverter, найденного в исходном коде JSON.NET, но с использованием IDictionary вместо ExpandoObject.

Использование:

var settings = new JsonSerializerSettings()
{
    Converters = { new DictionaryConverter() },
};
var result = JsonConvert.DeserializeObject<IDictionary<string, object>>(json, settings);

Код:

// based on ExpandoObjectConverter, but using arrays instead of IList, to behave similar to System.Web.Script.Serialization.JavaScriptSerializer
public class DictionaryConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        return ReadValue(reader);
    }

    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(IDictionary<string, object>));
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    private object ReadValue(JsonReader reader)
    {
        while (reader.TokenType == JsonToken.Comment)
        {
            if (!reader.Read())
                throw JsonSerializationExceptionCreate(reader, "Unexpected end when reading IDictionary<string, object>.");
        }

        switch (reader.TokenType)
        {
            case JsonToken.StartObject:
                return ReadObject(reader);
            case JsonToken.StartArray:
                return ReadList(reader);
            default:
                if (IsPrimitiveToken(reader.TokenType))
                    return reader.Value;

                throw JsonSerializationExceptionCreate(reader, string.Format(CultureInfo.InvariantCulture, "Unexpected token when converting IDictionary<string, object>: {0}", reader.TokenType));
        }
    }

    private object ReadList(JsonReader reader)
    {
        List<object> list = new List<object>();

        while (reader.Read())
        {
            switch (reader.TokenType)
            {
                case JsonToken.Comment:
                    break;
                default:
                    object v = ReadValue(reader);

                    list.Add(v);
                    break;
                case JsonToken.EndArray:
                    return list;
            }
        }

        throw JsonSerializationExceptionCreate(reader, "Unexpected end when reading IDictionary<string, object>.");
    }

    private object ReadObject(JsonReader reader)
    {
        IDictionary<string, object> dictionary = new Dictionary<string, object>();
        while (reader.Read())
        {
            switch (reader.TokenType)
            {
                case JsonToken.PropertyName:
                    string propertyName = reader.Value.ToString();

                    if (!reader.Read())
                        throw JsonSerializationExceptionCreate(reader, "Unexpected end when reading IDictionary<string, object>.");

                    object v = ReadValue(reader);

                    dictionary[propertyName] = v;
                    break;
                case JsonToken.Comment:
                    break;
                case JsonToken.EndObject:
                    return dictionary;
            }
        }

        throw JsonSerializationExceptionCreate(reader, "Unexpected end when reading IDictionary<string, object>.");
    }

    //based on internal Newtonsoft.Json.JsonReader.IsPrimitiveToken
    internal static bool IsPrimitiveToken(JsonToken token)
    {
        switch (token)
        {
            case JsonToken.Integer:
            case JsonToken.Float:
            case JsonToken.String:
            case JsonToken.Boolean:
            case JsonToken.Undefined:
            case JsonToken.Null:
            case JsonToken.Date:
            case JsonToken.Bytes:
                return true;
            default:
                return false;
        }
    }

    // based on internal Newtonsoft.Json.JsonSerializationException.Create
    private static JsonSerializationException JsonSerializationExceptionCreate(JsonReader reader, string message, Exception ex = null)
    {
        return JsonSerializationExceptionCreate(reader as IJsonLineInfo, reader.Path, message, ex);
    }

    // based on internal Newtonsoft.Json.JsonSerializationException.Create
    private static JsonSerializationException JsonSerializationExceptionCreate(IJsonLineInfo lineInfo, string path, string message, Exception ex)
    {
        message = JsonPositionFormatMessage(lineInfo, path, message);

        return new JsonSerializationException(message, ex);
    }

    // based on internal Newtonsoft.Json.JsonPosition.FormatMessage
    internal static string JsonPositionFormatMessage(IJsonLineInfo lineInfo, string path, string message)
    {
        if (!message.EndsWith(Environment.NewLine))
        {
            message = message.Trim();

            if (!message.EndsWith(".", StringComparison.Ordinal))
                message += ".";

            message += " ";
        }

        message += string.Format(CultureInfo.InvariantCulture, "Path '{0}'", path);

        if (lineInfo != null && lineInfo.HasLineInfo())
            message += string.Format(CultureInfo.InvariantCulture, ", line {0}, position {1}", lineInfo.LineNumber, lineInfo.LinePosition);

        message += ".";

        return message;
    }
}
1
ответ дан Rafał Kłys 22 August 2018 в 15:38
поделиться

Вы можете использовать Tiny-JSON

string json = "{\"key1\":\"value1\", \"key2\":\"value2\"}";
IDictionary<string, string> dict = Tiny.Json.Decode<Dictionary<string, string>>(json);
0
ответ дан Robse 22 August 2018 в 15:38
поделиться

Изменить: это работает, но принятый ответ с использованием Json.NET гораздо более прост. Оставляя это на случай, если кому-то нужен только код BCL.

Он не поддерживается платформой .NET из коробки. Взгляд надзора - не всем нужно десериализовать объекты с именованными свойствами. Итак, я закончил свой собственный:

<Serializable()> Public Class StringStringDictionary
    Implements ISerializable
    Public dict As System.Collections.Generic.Dictionary(Of String, String)
    Public Sub New()
        dict = New System.Collections.Generic.Dictionary(Of String, String)
    End Sub
    Protected Sub New(info As SerializationInfo, _
          context As StreamingContext)
        dict = New System.Collections.Generic.Dictionary(Of String, String)
        For Each entry As SerializationEntry In info
            dict.Add(entry.Name, DirectCast(entry.Value, String))
        Next
    End Sub
    Public Sub GetObjectData(info As SerializationInfo, context As StreamingContext) Implements ISerializable.GetObjectData
        For Each key As String in dict.Keys
            info.AddValue(key, dict.Item(key))
        Next
    End Sub
End Class

Вызывается с помощью:

string MyJsonString = "{ \"key1\": \"value1\", \"key2\": \"value2\"}";
System.Runtime.Serialization.Json.DataContractJsonSerializer dcjs = new
  System.Runtime.Serialization.Json.DataContractJsonSerializer(
    typeof(StringStringDictionary));
System.IO.MemoryStream ms = new
  System.IO.MemoryStream(Encoding.UTF8.GetBytes(MyJsonString));
StringStringDictionary myfields = (StringStringDictionary)dcjs.ReadObject(ms);
Response.Write("Value of key2: " + myfields.dict["key2"]);

Извините за сочетание C # и VB.NET ...

5
ответ дан Rory O'Kane 22 August 2018 в 15:38
поделиться
  • 1
    [TestMethod] public void TestSimpleObject () {const string json = @ & quot; & quot; Название & quot; & quot; & quot; & quot; Боб & quot ;, & quot; Возраст & quot; & quot; 42} & quot ;; var dict = new JavaScriptSerializer (). DeserializeObject (json) как IDictionary & lt; string, object & gt ;; Assert.IsNotNull (ДИКТ); Assert.IsTrue (dict.ContainsKey (& Quot; Имя & Quot;)); Assert.AreEqual («Боб», dict [«Имя»]); Assert.IsTrue (dict.ContainsKey (& Quot; Возраст & Quot;)); Assert.AreEqual (42, dict [«Возраст»]); } – Mark Rendle 22 September 2010 в 10:28
  • 2
    Это фантастика. Помогает с реализацией сервисов WCF, которые взаимодействуют с JSON с браузерами. – Anton 6 January 2011 в 02:26
  • 3
    @Mark Rendle: ваша реализация настолько проста, и является ТОЛЬКО той, которая до сих пор работала для меня как для получения результатов успеха, так и для кодов ошибок. Я пробовал много решений, так что спасибо за сообщение в качестве комментария. Это должен быть ответ. – Bryan 20 March 2015 в 01:02

Я добавил проверку нулевых значений в JSON на другой ответ

У меня была такая же проблема, поэтому я написал это сам. Это решение отличается от других ответов, поскольку оно может десериализоваться на нескольких уровнях.

Просто отправьте строку json в функцию deserializeToDictionary , она вернет не строго типизированный объект Dictionary<string, object> .

private Dictionary<string, object> deserializeToDictionary(string jo)
{
    var values = JsonConvert.DeserializeObject<Dictionary<string, object>>(jo);
    var values2 = new Dictionary<string, object>();
    foreach (KeyValuePair<string, object> d in values)
    {
        if (d.Value != null && d.Value.GetType().FullName.Contains("Newtonsoft.Json.Linq.JObject"))
        {
            values2.Add(d.Key, deserializeToDictionary(d.Value.ToString()));
        }
        else
        {
            values2.Add(d.Key, d.Value);
        }
    }
    return values2;
}

Ex: Это вернет объект Dictionary<string, object> ответа JSON в Facebook.

private void button1_Click(object sender, EventArgs e)
{
    string responsestring = "{\"id\":\"721055828\",\"name\":\"Dasun Sameera
        Weerasinghe\",\"first_name\":\"Dasun\",\"middle_name\":\"Sameera\",\"last_name\":\"Weerasinghe\",\"username\":\"dasun\",\"gender\":\"male\",\"locale\":\"en_US\",
        hometown: {id: \"108388329191258\", name: \"Moratuwa, Sri Lanka\",}}";
    Dictionary<string, object> values = deserializeToDictionary(responsestring);
}

Примечание: родной город далее deserialize в объект Dictionary<string, object>.

4
ответ дан TotPeRo 22 August 2018 в 15:38
поделиться
  • 1
    +1 Как я сказал с Дасуном выше. Вы можете просто проверить, есть ли d.Value is JObject. Вам не нужно проходить рефлексию для проверки типов. А с помощью оператора is вам не нужно проверять значение null. Он возвращает false, если объект имеет значение null. – Jordan 3 March 2015 в 17:34
Другие вопросы по тегам:

Похожие вопросы: