#c# #linq #json #serialization #json.net
#c# #linq #json #сериализация #json.net
Вопрос:
Я пытаюсь правильно написать код для построения структуры данных для сериализации в json.
Я использую json.net .
Я не хочу создавать кучу классов для хранения этих данных, поскольку я думал, что должны быть некоторые классы, которые уже будут делать это в json.net
У меня уже есть все необходимые данные в серии вложенных циклов, и теперь я просто хочу добавить их в иерархию объектов, прежде чем запускать на ней JsonConvert.SerializeObject.
Я уже пробовал подобный код, но, похоже, он не работает
JArray container = new JArray();
container.Add(new JObject(new JProperty("name", "Client1"), new JProperty("projects", new JArray())));
container[0].AddAfterSelf(new JObject(new JProperty("projects", new JArray())));
container[1].AddAfterSelf(new JObject(new JProperty("projects", "Project2")));
container[1].AddAfterSelf(new JObject(new JProperty("projects", "Project3")));
container.Add(new JProperty("name", "Client2"));
var test = JsonConvert.SerializeObject(container);
Проблема в том, что когда я использую [i]. или ElementAt(i) для доступа к чему-либо в структуре, либо .Add() отсутствует, либо .ElementAt отсутствует.
Как мне пошагово перейти к структуре данных, чтобы это красиво отображало нижеприведенное, или мне нужно создать свой собственный класс контейнера для всего этого?
Это формат данных, который я пытаюсь создать.
[
{
"name": "student1",
"projects":
[
{
"name": "Project1",
"tasks":
[
{
"name": "task1",
"id": 2
}
],
"id": 6
}
]
},
{
"name": "Student2",
"projects": [
{
"name": "Project1",
"tasks": [
{
"name": "Task2",
"id": 1
},
{
"name": "Task3",
"id": 3
},
{
"name": "Task4",
"id": 4
}
],
"id": 2
и т.д…
Ответ №1:
Я думаю, вы спрашиваете, как сериализовать сложные бизнес-объекты в json, но предоставлять только определенные свойства.
Другими словами, у вас уже есть список студентов, но вы хотите отправить только очень конкретные данные через json. Если я ошибаюсь, этот ответ не удовлетворит вашим потребностям.
Итак, предполагая, что у вас есть список студентов со свойством projects, которое имеет внутреннее свойство tasks, вот как я это делаю без необходимости создавать множество новых классов, я использую анонимные объекты.
После того, как я создал свой список анонимных объектов, я просто превращаю их в строку json.
Как указано в комментариях, вам не нужно использовать json.net эта функциональность доступна во фреймворке, добавьте ссылку на System.Web.Extensions.dll
затем
используя System.Web.Script.Сериализация;
var jsonStudents = new List<object>();
foreach (var student in students)
{
jsonStudents.Add(new
{
student.Id, //anonymous properties automatically pick up the name of the property you pass them, this will be called Id
FullName = student.FirstName " " student.LastName, //if you want to name a property yourself use this notation
Projects = student.Projects.Select(p => new //this will be an enumerable of nested anonymous objects, we're partially selecting project properties
{
p.Id,
p.Name,
Tasks = p.Tasks.Select(t => new //nesting another level
{
t.Id,
t.Name
})
})
});
}
var serializer = new JavaScriptSerializer();
var jsonString = serializer.Serialize(jsonStudents);
Если вы действительно хотите использовать циклы, вы можете сделать это, чтобы позволить вам выполнять более сложные задачи при создании проектов и задач:
var jsonStudents = new List<object>();
foreach (var student in students)
{
var tempStudent = new
{
student.Id, //anonymous properties automatically pick up the name of the property you pass them, this will be called Id
FullName = student.FirstName " " student.LastName, //if you want to name a property yourself use this notation
Projects = new List<object>()
};
foreach (var project in student.Projects)
{
var tempProject = new {
project.Id,
project.Name,
Tasks = new List<object>()
};
foreach (var task in project.Tasks)
{
tempProject.Tasks.Add(new {
task.Id,
task.Name
});
}
tempStudent.Projects.Add(tempProject);
}
jsonStudents.Add(tempStudent);
}
var serializer = new JavaScriptSerializer();
var jsonString = serializer.Serialize(jsonStudents);
Комментарии:
1. Хм, это выглядит довольно умно и, похоже, зависит от отношений linq2sql. Отличное решение. Вы знаете, помогает ли это с производительностью, поскольку компилятор должен знать, какие свойства ему нужны для вложенных объектов, и, как таковой, может быть умным с запросом (скорее вопрос linq2sql) Я планировал оптимизировать свой доступ к данным, как только это заработает.
2. Я использовал это с POCOs, Linq2SQL и с LinqToEntities, вы можете сделать это с любым . Сетевой объект. В моем ответе на самом деле нет Linq2SQL, я не совсем уверен, что вы имеете в виду, хотя я думаю, что вы используете Linq2SQL, когда имеете в виду просто Linq. С точки зрения производительности анонимные классы фактически объявлены в IL afaik, так что на самом деле это просто экономия строк кода, все остальное — это в значительной степени то, что вам пришлось бы делать, если бы вы делали это с использованием моделей, как вы описали.
3. ИМО, это лучший ответ… Вам даже не нужно json.net для этого просто используйте встроенный сериализатор json
4. Причина, по которой я упомянул Linq2SQL, заключалась в студенте. Вызов проектов, откуда student знает, что он может ссылаться на проекты?
5. Я предполагаю, что на самом деле это что-то анонимное. Но поможет ли этот ответ мне с моей серией вложенных циклов? Что, если я захочу получить еще немного данных в середине инструкции?
Ответ №2:
это код, который генерирует точный вывод из вашего вопроса (требуется using Newtonsoft.Json.Linq;
):
var json = new JArray(
new JObject(
new JProperty("name", "student1"),
new JProperty("projects",
new JArray(
new JObject(
new JProperty("name", "Project1"),
new JProperty("tasks",
new JArray(
new JObject(
new JProperty("name", "task1"),
new JProperty("id", 2)
)
)
),
new JProperty("id", 6)
)
)
)
),
new JObject(
new JProperty("name", "student2"),
new JProperty("projects",
new JArray(
new JObject(
new JProperty("name", "Project1"),
new JProperty("tasks",
new JArray(
new JObject(
new JProperty("name", "task2"),
new JProperty("id", 1)
),
new JObject(
new JProperty("name", "task3"),
new JProperty("id", 3)
),
new JObject(
new JProperty("name", "task4"),
new JProperty("id", 4)
)
)
),
new JProperty("id", 2)
)
)
)
)
);
var jsonString = json.ToString();
Я полагаю, используя Json.Синтаксис Net Linq имеет большое преимущество в том, что результирующий код C # может быть отформатирован так, чтобы он имел почти ту же структуру, что и JSON, который вы пытаетесь сгенерировать.
Обновить
Если вы хотите манипулировать объектом Json после его создания, посмотрите на этот пример, который создает внешний массив только с одним студентом, а затем добавляет еще один:
// create an isolated Student instance:
var student2 = new JObject(
new JProperty("name", "student2"),
new JProperty("projects",
new JArray(
new JObject(
new JProperty("name", "Project1"),
new JProperty("tasks",
new JArray(
new JObject(
new JProperty("name", "task2"),
new JProperty("id", 1)
),
new JObject(
new JProperty("name", "task3"),
new JProperty("id", 3)
),
new JObject(
new JProperty("name", "task4"),
new JProperty("id", 4)
)
)
),
new JProperty("id", 2)
)
)
)
);
var json = new JArray(
new JObject(
new JProperty("name", "student1"),
new JProperty("projects",
new JArray(
new JObject(
new JProperty("name", "Project1"),
new JProperty("tasks",
new JArray(
new JObject(
new JProperty("name", "task1"),
new JProperty("id", 2)
)
)
),
new JProperty("id", 6)
)
)
)
)
);
// now, add the student2 instance to the array:
json // which is an JArray
.Last // gets the last Array item, i.e. "student1"
.AddAfterSelf(student2); // adds this which hence becomes the new last one
Идея в том, что вы можете применить тот же принцип к любой другой части структуры таким же образом.
HTH…
Комментарии:
1. Привет, спасибо за ответ, но я хочу собрать json в серии циклов, т. е. не все одновременно? Если я должен сделать это таким образом, я думаю, что я должен построить это за один шаг, правильно? Или я могу изменить структуру данных после того, как она была построена?
2. Нет, вам не обязательно создавать все это за один шаг, вы также можете изменить структуру позже. Смотрите мой обновленный ответ выше.
3. Хорошо, это ближе к тому, что мне нужно, но что, если я захочу добавить элементы дальше по дереву? А что, если я хочу добавить, а не AddAfterSelf? У меня запущена серия вложенных циклов, выполняющих доступ к данным (я понимаю, что это может негативно сказаться на производительности, но я пока не пытаюсь решить эту проблему). Я надеюсь, что это имеет смысл. Когда я пытаюсь выполнить container.Last.Last.AddAfterSelf(new JObject(new JProperty(«test», «TestItem»))); Я получаю сообщение об ошибке Не удается добавить Newtonsoft.Json.Linq.JObject в Newtonsoft.Json.Linq.JObject. Вы видите, что я пытаюсь сделать?
4. Ошибка возникает из-за того, что
container.Last.Last
возвращает свойство «projects», следовательно, вы можете добавить другоеJProperty
только после этого, а неJObject
. Если вы действительно хотели добавить новыйJObject
в массив «проекты», сделайте это:container.Last.SelectToken("projects").Last.AddAfterSelf(new JObject(...))
. Это возвращает свойство «projects» из последнего элемента в контейнере и добавляет новоеJObject
в массив «projects». Итак, с помощью комбинации свойствFirst
иLast
и методовSelectToken()
andAddAfterSelf()
вы должны быть в состоянии достичь того, что вам нужно.5. Это кажется таким близким! Теперь массиву, похоже, это не нравится, потому что он пуст, поэтому . Последний не может выбрать что добавить после? Если вы можете сказать мне, как сделать это другим способом, я могу это сделать, большое спасибо за всю вашу помощь!
Ответ №3:
В итоге я использовал эти модели.
public class JStudent
{
public List<JProject> projects = new List<JProject>();
public string name;
public string id;
}
public class JProject
{
public List<JTask> tasks = new List<JTask>();
public string name;
public string id;
}
public class JTask
{
public string name;
public string id;
}
Теперь это работает отлично. Есть ли лучший способ сделать это?
Комментарии:
1. На вашем месте я бы просто построил вашу иерархию объектов, как вы делаете здесь, и оставил бы всю сериализацию json.net . Если у вас есть особые потребности в сериализации, вы можете управлять этим с помощью атрибутов: james.newtonking.com/projects/json/help
2. Почему этот ответ не проголосован выше? Это абсолютно потрясающе. Спасибо!