2008-10-14 2 views
8

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

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

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

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

Я не знаю, возможно ли это, поскольку C# не является динамическим, и компилятор фактически преобразует Инициализатор объектов в d Anonymous Type into strongly typed code that can run. This is explained in этой статье.

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

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

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

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

ответ

6

Есть языки для .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 
+0

+1, грязный, но в настоящее время единственный способ сделать то, что хочет OP. – user7116 2008-10-14 02:38:25

+0

Очень приятно, это один из способов, о котором я не думал. – 2008-10-14 03:15:40

0

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

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

  • Первый; для создания прозрачного метода, о котором вы говорите, может потребоваться много кода поддержки с использованием отражения и т. д.

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

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

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

:)

5

Вы должны проверить Json.NET проекта:

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

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

1

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

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

4

Я написал относительно короткий метод, который будет обрабатывать 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; 
} 

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

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

Смежные вопросы