Можете ли вы создать экземпляр объекта из JSON в.NET?
Поскольку инициализаторы объектов очень похожи на JSON, и теперь в.NET есть анонимные типы. Было бы здорово иметь возможность взять строку, такую как JSON, и создать анонимный объект, который представляет строку JSON.
Используйте инициализаторы объектов для создания анонимного типа:
var person = new {
FirstName = "Chris",
LastName = "Johnson"
};
Было бы здорово, если бы вы могли передать строковое представление кода Object Initializer (предпочтительно что-то вроде JSON), чтобы создать экземпляр Anonymous Type с этими данными.
Я не знаю, возможно ли это, поскольку C# не является динамическим, и компилятор фактически преобразует инициализатор объекта и анонимный тип в строго типизированный код, который может выполняться. Это объясняется в этой статье.
Может быть, функциональность взять JSON и создать словарь ключ / значение с ним будет работать лучше всего.
Я знаю, что вы можете сериализовать / десериализовать объект в JSON в.NET, но я ищу способ создания объекта, который по существу свободно типизирован, подобно тому, как работает JavaScript.
Кто-нибудь знает лучшее решение для этого в.NET?
ОБНОВЛЕНИЕ: слишком ясно, чтобы объяснить контекст, почему я спрашиваю об этом... Я думал о том, как C# может лучше поддерживать JSON на уровне языка (возможно), и я пытался придумать, как это можно сделать сегодня, для концептуального причины. Итак, я решил опубликовать это здесь, чтобы начать обсуждение.
5 ответов
Существуют языки для.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
Вы должны проверить проект JSON.net:
http://james.newtonking.com/pages/json-net.aspx
Вы в основном говорите о способности увлажнять объект из JSON, что и будет делать. Он не будет делать анонимные типы, но, возможно, он подберет вас достаточно близко.
Я написал относительно короткий метод, который будет анализировать 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;
}
Я знаю, что этот метод может быть немного грубым, и, возможно, его можно немного оптимизировать, но это первый проект, и он просто работает.
Кроме того, прежде чем жаловаться на то, что он не использует регулярные выражения, имейте в виду, что не все действительно понимают регулярные выражения, и написание этого таким образом усложнит для других исправление, если это необходимо. Кроме того, в настоящее время я не слишком хорошо знаю регулярные выражения, и разбор строк был проще.
Вы не можете вернуть анонимный тип из метода **, поэтому существование "перегидратированного" анонимного типа будет ограничено методом, в котором он перегидрируется. Вроде бессмысленно.
** Вы можете вернуть его как объект (который требует отражения, чтобы получить доступ к его свойствам - yeech), или вы можете "привести его в пример", что также бессмысленно, поскольку оно требует дополнительных шагов и означает, что вы уже ЗНАЕТЕ, что тип объекта должен выглядеть так, почему бы просто не создать объект и не заполнить его в первую очередь?
Какое приложение для этого?
Я бы не пошел по этому пути по нескольким причинам.
Первый; для создания прозрачного метода, о котором вы говорите, может потребоваться много кода поддержки, использующего рефлексию.
Во-вторых, как вы сказали, C# является строго типизированным языком, и подобные вещи по какой-то причине были исключены из спецификации языка.
В-третьих, накладные расходы на это не стоили бы того. Помните, что веб-страницы (особенно AJAX-запросы) должны быть очень быстрыми, или это противоречит цели. Если вы потратите 50% на сериализацию ваших объектов между C# и Javascript, у вас возникнут проблемы.
Мое решение было бы создать класс, который просто инкапсулирует словарь и который принимает строку JSON в качестве аргумента ctor. Затем просто расширьте этот класс для каждого типа JSON-запроса, который вы хотите обработать. Это будет строго типизированное и более быстрое решение, но сохраняющее расширяемость и простоту использования. Недостатком является то, что для каждого типа запроса JSON требуется написать больше кода.
:)