Можете ли вы создать экземпляр объекта из JSON в .NET?
-
11-07-2019 - |
Вопрос
Поскольку инициализаторы объектов очень похожи на JSON, и теперь в .NET есть анонимные типы.Было бы здорово иметь возможность взять строку, такую как JSON, и создать анонимный объект, представляющий строку JSON.
Используйте инициализаторы объектов для создания анонимного типа:
var person = new {
FirstName = "Chris",
LastName = "Johnson"
};
Было бы здорово, если бы вы могли передать строковое представление кода инициализатора объекта (предпочтительно что-то вроде JSON) для создания экземпляра анонимного типа с этими данными.
Я не знаю, возможно ли это, поскольку C # не является динамическим, и компилятор фактически преобразует инициализатор объекта вd Анонимный ввод в строго типизированный код, который может выполняться.Это объясняется в эта статья.
Возможно, функциональность для использования JSON и создания с его помощью словаря ключей / значений сработала бы лучше всего.
Я знаю, что вы можете сериализовать / десериализовать объект в JSON в .NET, но то, что я ищу, - это способ создать объект, который по существу является свободно типизированным, аналогично тому, как работает JavaScript.
Кто-нибудь знает лучшее решение для этого в .NET?
Обновить:Слишком проясните контекст того, почему я спрашиваю об этом...Я думал о том, как C # мог бы лучше поддерживать JSON на уровне языка (возможно), и я пытался придумать способы, которыми это можно было бы сделать сегодня, по концептуальным причинам.Итак, я решил опубликовать это здесь, чтобы начать обсуждение.
Решение
Существуют языки для .NET, в которых используется утиный ввод, но в C # это невозможно с использованием точечной нотации, поскольку C # требует, чтобы все ссылки на элементы разрешались во время компиляции.Если вы хотите использовать точечную нотацию, вам все равно придется где-то определить класс с требуемыми свойствами и использовать любой метод, который вы хотите создать для создания экземпляра класса из данных 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 требуется написать больше кода.
:)