Можете ли вы создать экземпляр объекта из JSON в .NET? - PullRequest
8 голосов
/ 14 октября 2008

Поскольку инициализаторы объектов очень похожи на JSON, и теперь в .NET есть анонимные типы. Было бы здорово иметь возможность взять строку, такую ​​как JSON, и создать анонимный объект, который представляет строку JSON.

Используйте инициализаторы объектов для создания анонимного типа:

var person = new {
    FirstName = "Chris",
    LastName = "Johnson"
};

Было бы замечательно, если бы вы могли передать строковое представление кода Object Initializer (предпочтительно что-то вроде JSON) для создания экземпляра анонимного типа с этими данными.

Я не знаю, возможно ли это, поскольку C # не является динамическим, и компилятор фактически преобразует инициализатор объекта d анонимного типа в строго типизированный код, который может выполняться. Это объясняется в этой статье.

Может быть, лучше всего использовать JSON и создать словарь ключ / значение с ним.

Я знаю, что вы можете сериализовать / десериализовать объект в JSON в .NET, но я ищу способ создания объекта, который по существу свободно напечатан, подобно тому, как работает JavaScript.

Кто-нибудь знает лучшее решение для этого в .NET?

ОБНОВЛЕНИЕ: Слишком уточнить контекст, почему я спрашиваю об этом ... Я думал о том, как C # может лучше поддерживать JSON на уровне языка (возможно), и я пытался придумать, как это можно сделать сегодня по концептуальным причинам. Итак, я решил опубликовать это здесь, чтобы начать обсуждение.

Ответы [ 5 ]

6 голосов
/ 14 октября 2008

Существуют языки для .NET, которые имеют типизацию утилит, но это невозможно с C # с использованием Dot.Notation, поскольку C # требует, чтобы все ссылки на члены были разрешены во время компиляции. Если вы хотите использовать Dot.Notation, вам все равно нужно где-то определить класс с необходимыми свойствами и использовать любой метод, который вы хотите создать для экземпляра класса из данных JSON. Предварительное определение класса имеет такие преимущества, как строгая типизация, поддержка IDE, в том числе intellisense, и отсутствие проблем с орфографическими ошибками. Вы все еще можете использовать анонимные типы:

 T deserialize<T>(string jsonStr, T obj) { /* ... */}

 var jsonString = "{FirstName='Chris', LastName='Johnson, Other='unused'}";
 var person     = deserialize(jsonString, new {FirstName="",LastName=""});
 var x          = person.FirstName; //strongly-typed
5 голосов
/ 14 октября 2008

Вы должны проверить проект JSON.net :

http://james.newtonking.com/pages/json-net.aspx

Вы в основном говорите о способности гидратировать объект из JSON, что и будет делать. Он не будет работать с анонимными типами, но, возможно, он подберет вас достаточно близко.

4 голосов
/ 14 октября 2008

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

Вот пример использования приведенного ниже метода:

var obj = ParseJsonToDictionary("{FirstName: \"Chris\", \"Address\":{Street:\"My Street\",Number:123}}");

// Access the Address.Number value
object streetNumber = ((Dictionary<string, object>)obj["Address"])["Number"];

И вот код для метода ParseJsonToDictionary:

public static Dictionary<string, object> ParseJsonToDictionary(string json)
{
    var d = new Dictionary<string, object>();

    if (json.StartsWith("{"))
    {
        json = json.Remove(0, 1);
        if (json.EndsWith("}"))
            json = json.Substring(0, json.Length - 1);
    }
    json.Trim();

    // Parse out Object Properties from JSON
    while (json.Length > 0)
    {
        var beginProp = json.Substring(0, json.IndexOf(':'));
        json = json.Substring(beginProp.Length);

        var indexOfComma = json.IndexOf(',');
        string endProp;
        if (indexOfComma > -1)
        {
            endProp = json.Substring(0, indexOfComma);
            json = json.Substring(endProp.Length);
        }
        else
        {
            endProp = json;
            json = string.Empty;
        }

        var curlyIndex = endProp.IndexOf('{');
        if (curlyIndex > -1)
        {
            var curlyCount = 1;
            while (endProp.Substring(curlyIndex + 1).IndexOf("{") > -1)
            {
                curlyCount++;
                curlyIndex = endProp.Substring(curlyIndex + 1).IndexOf("{");
            }
            while (curlyCount > 0)
            {
                endProp += json.Substring(0, json.IndexOf('}') + 1);
                json = json.Remove(0, json.IndexOf('}') + 1);
                curlyCount--;
            }
        }

        json = json.Trim();
        if (json.StartsWith(","))
            json = json.Remove(0, 1);
        json.Trim();


        // Individual Property (Name/Value Pair) Is Isolated
        var s = (beginProp + endProp).Trim();


        // Now parse the name/value pair out and put into Dictionary
        var name = s.Substring(0, s.IndexOf(":")).Trim();
        var value = s.Substring(name.Length + 1).Trim();

        if (name.StartsWith("\"") && name.EndsWith("\""))
        {
            name = name.Substring(1, name.Length - 2);
        }

        double valueNumberCheck;
        if (value.StartsWith("\"") && value.StartsWith("\""))
        {
            // String Value
            d.Add(name, value.Substring(1, value.Length - 2));
        }
        else if (value.StartsWith("{") && value.EndsWith("}"))
        {
            // JSON Value
            d.Add(name, ParseJsonToDictionary(value));
        }
        else if (double.TryParse(value, out valueNumberCheck))
        {
            // Numeric Value
            d.Add(name, valueNumberCheck);
        }
        else
            d.Add(name, value);
    }

    return d;
}

Я знаю, что этот метод может быть немного грубым, и, возможно, его можно немного оптимизировать, но это первый черновик, и он просто работает.

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

1 голос
/ 14 октября 2008

Вы не можете вернуть анонимный тип из метода **, поэтому существование "повторно сгенерированного" анонимного типа будет ограничено методом, с помощью которого он будет повторно сгенерирован. Вид бессмысленный.

** Вы можете вернуть его как объект (который требует отражения, чтобы получить доступ к его свойствам - yeech), или вы можете «привести его в пример», что также бессмысленно, поскольку требует дополнительных шагов и означает, что вы уже ЗНАЙТЕ, как должен выглядеть тип объекта, так почему бы просто не создать объект и не заполнить его в первую очередь?

0 голосов
/ 14 октября 2008

Какое приложение для этого?

Я бы не пошел по этому пути по нескольким причинам.

  • Во-первых; для создания прозрачного метода, о котором вы говорите, может потребоваться много кода поддержки, использующего рефлексию, и тому подобное.

  • Во-вторых, как вы сказали, C # - это язык со строгой типизацией, и подобные причины по какой-то причине были исключены из спецификации языка.

  • В-третьих, затраты на это не стоили бы. Помните, что веб-страницы (особенно AJAX-запросы) должны быть очень быстрыми, или это противоречит цели. Если вы потратите 50% на сериализацию ваших объектов между C # и Javascript, у вас возникнет проблема.

Мое решение было бы создать класс, который просто инкапсулирует словарь и который принимает строку JSON в качестве аргумента ctor. Затем просто расширьте этот класс для каждого типа JSON-запроса, который вы хотите обработать. Это будет строго типизированное и более быстрое решение, но сохраняющее расширяемость и простоту использования. Недостатком является то, что для каждого типа запроса JSON требуется написать больше кода.

:)

...