Behandle serialisering og deserialisering av komplekse objekter
Når du arbeider med komplekse objekter, JsonSerializerOptions kan klasse- og dataoverføringsobjekter (DTOer) brukes til å unngå behandling av problemer. Komplekse objekter inneholder ofte nestede strukturer, spesielle datatyper eller krever bestemte konfigurasjoner for å håndtere serialisering og deserialisering effektivt. Klassen JsonSerializerOptions inneholder ulike egenskaper som kan tilpasses for å løse disse utfordringene. Egenskaper kan for eksempel brukes til å legge til egendefinerte konverteringsprogrammer, aktivere egenskapssamsvar som ikke skiller mellom store og små bokstaver, eller håndtere nullverdier. DTOer fungerer derimot som mellomliggende objekter som forenkler overføringen av data mellom ulike lag i et program, slik at strukturen og typene av dataene er konsekvente og håndterbare. Ved å utnytte JsonSerializerOptions og DTOer kan utviklere oppnå mer pålitelig og effektiv serialisering og deserialisering av komplekse JavaScript Object Notation -data (JSON), noe som gjør det enklere å arbeide med og integrere i programmene sine.
Bruk JsonSerializerOptions-klassen til å serialisere komplekse objekter
Klassen JsonSerializerOptions er en del av navneområdet System.Text.Json og gir en måte å konfigurere virkemåten til JSON-serialisering og deserialisering på. Den lar deg tilpasse ulike aspekter ved serialiseringsprosessen, for eksempel hvordan egenskaper håndteres, hvordan referanser administreres og hvordan spesielle datatyper behandles.
Klassen JsonSerializerOptions er nyttig når du arbeider med komplekse objekter, da den gir alternativer for å håndtere nestede strukturer, sirkelreferanser og andre serialiseringsutfordringer.
Følgende egenskaper demonstreres under denne enheten:
- MaxDepth: Denne egenskapen angir maksimal dybde som tillates når du leser eller skriver JSON. Det kan bidra til å forhindre problemer med dypt nestede objekter som kan føre til stakkoverflyt eller ytelsesproblemer.
- ReferenceHandler: Med denne egenskapen kan du angi hvordan referanser til objekter håndteres under serialisering og deserialisering. Det kan være nyttig når du arbeider med sirkelreferanser eller komplekse objektgrafer.
En annen egenskap som hjelper deg med å serialisere og deserialisere komplekse objekter, er Converters. Med denne egenskapen kan du legge til egendefinerte konverteringsprogrammer for å håndtere bestemte typer eller komplekse objekter. Du kan for eksempel opprette et egendefinert konverteringsprogram for en klasse som inneholder nestede objekter eller komplekse egenskaper.
Bruk egenskapen JsonSerializerOptions.ReferenceHandler
Egenskapen ReferenceHandler brukes til å angi hvordan referanser til objekter håndteres under serialisering og deserialisering. Dette er spesielt nyttig når du arbeider med komplekse objektgrafer som kan inneholde sirkelreferanser eller delte referanser.
En sirkelreferanse oppstår når to eller flere objekter refererer til hverandre og oppretter en løkke. Hvis du for eksempel har et objekt A som refererer til objekt B, og objektreferanseobjekt BA, oppretter dette en sirkelreferanse. Når du serialiserer slike objekter, kan serialisereren støte på en uendelig løkke som fører til en stakkoverflytfeil.
Vurder følgende kodeeksempel som demonstrerer en sirkelreferanse mellom to klasser:
public class Person
{
public string Name { get; set; }
public List<Pet> Pets { get; set; }
}
public class Pet
{
public string Name { get; set; }
public Person Owner { get; set; }
}
I dette eksemplet Person har klassen en liste over Pet objekter, og hvert Pet objekt har en referanse tilbake til eieren ().Person Dette oppretter en sirkelreferanse når du serialiserer eller deserialiserer objektene.
Serialisering av Person objektet med standardinnstillingene resulterer i en JsonException på grunn av sirkelreferansen. Hvis du vil håndtere dette, kan du bruke egenskapen for ReferenceHandlerJsonSerializerOptions klassen.
var options = new JsonSerializerOptions
{
ReferenceHandler = ReferenceHandler.Preserve,
WriteIndented = true
};
var person = new Person
{
Name = "John",
Pets = new List<Pet>
{
new Pet { Name = "Fido", Owner = null },
new Pet { Name = "Whiskers", Owner = null }
}
};
person.Pets[0].Owner = person;
person.Pets[1].Owner = person;
var json = JsonSerializer.Serialize(person, options);
Console.WriteLine(json);
/*
OUTPUT (with WriteIndented = true):
{
"$id": "1",
"Name": "John",
"Pets": {
"$id": "2",
"$values": [
{
"$id": "3",
"Name": "Fido",
"Owner": {
"$ref": "1"
}
},
{
"$id": "4",
"Name": "Whiskers",
"Owner": {
"$ref": "1"
}
}
]
}
}
*/
I dette eksemplet ReferenceHandler.Preserve brukes alternativet til å håndtere sirkelreferanser. Serialisereren inkluderer en $id egenskap i JSON-utdataene for å representere referansen, slik at den kan deserialiseres riktig.
Når du deserialiserer, ReferenceHandler.Preserve sikrer alternativet også at referansene gjenopprettes på riktig måte, slik at dupliserte objekter ikke opprettes.
var deserializedPerson = JsonSerializer.Deserialize<Person>(json, options);
Console.WriteLine($"Name: {deserializedPerson.Name}");
foreach (var pet in deserializedPerson.Pets)
{
Console.WriteLine($"Pet Name: {pet.Name}, Owner: {pet.Owner.Name}");
}
/*
OUTPUT:
Name: John
Pet Name: Fido, Owner: John
Pet Name: Whiskers, Owner: John
*/
I dette eksemplet har det deserialiserte Person objektet de samme referansene som det opprinnelige objektet, og beholder relasjonene mellom Person objektene og Pet objektene.
Bruke dataoverføringsobjekter til å serialisere og deserialisere komplekse objekter
Dataoverføringsobjekter brukes ofte i scenarioer der du må serialisere og deserialisere komplekse objekter.
DTOer gir følgende fordeler:
- Forenklet datastruktur: DTOer kan forenkle datastrukturen ved å flate ut nestede objekter eller fjerne unødvendige egenskaper. Dette gjør det enklere å serialisere og deserialisere dataene uten å håndtere komplekse objektgrafer.
- Selektiv serialisering: DTOer lar deg kontrollere hvilke egenskaper som er inkludert i de serialiserte utdataene. Dette kan bidra til å redusere størrelsen på de serialiserte dataene og forbedre ytelsen.
- Frakobling: DTOer kobler fra datastrukturen fra forretningslogikken, noe som gjør det enklere å administrere og vedlikeholde koden. Denne fordelingen av bekymringer gjør det også enklere å endre serialiseringsformatet uten å påvirke resten av programmet.
- Datakontrakter: DTOer fungerer som datakontrakter, og definerer strukturen til dataene som er serialisert og deserialisert. Dette gjør det enklere å sikre konsekvens og kompatibilitet mellom ulike deler av programmet eller mellom ulike programmer.
- Interoperabilitet: DTOer kan bidra til å sikre at datastrukturen er kompatibel med andre systemer eller tjenester, noe som gjør det enklere å integrere med eksterne API-er eller tjenester.
- Versjonskontroll: DTOer kan hjelpe deg med å administrere versjonskontroll av datastrukturer, slik at du kan utvikle datamodellen uten å bryte eksisterende klienter eller tjenester.
- Sikkerhet: DTOer kan bidra til å forbedre sikkerheten ved å begrense eksponeringen av interne datastrukturer. Ved hjelp av DTOer kan du kontrollere hvilke egenskaper som serialiseres og deserialiseres, noe som reduserer risikoen for å eksponere sensitiv informasjon.
- Ytelse: DTOer kan bidra til å forbedre ytelsen ved å redusere mengden data som overføres over nettverket. Ved hjelp av DTOer kan du serialisere bare de nødvendige egenskapene, redusere størrelsen på de serialiserte dataene og forbedre ytelsen.
Du kan selektivt serialisere deler av et objekt ved å opprette en egendefinert DTO som bare inneholder egenskapene du vil serialisere. Med denne fremgangsmåten kan du kontrollere nøyaktig hva som blir serialisert uten å inkludere nestede objekter.
Opprette og bruke DTOer for serialisering
Her er en trinnvis veiledning for hvordan du oppretter og bruker DTOer for serialisering i C#:
- Definer DTO: Opprett en klasse som bare inneholder egenskapene og metoderesultatene du vil serialisere.
- Tilordne det opprinnelige objektet til DTO: Opprett en metode for å tilordne det opprinnelige objektet til DTO. Denne metoden trekker ut de nødvendige dataene fra det opprinnelige objektet og fyller ut DTO-en.
- Serialiser DTO: Bruk
JsonSerializerklassen til å serialisere DTO-en til en JSON-streng. - Deserialiser DTO: Bruk
JsonSerializerklassen til å deserialisere JSON-strengen tilbake til DTO. - Tilordne DTO tilbake til det opprinnelige objektet: Opprett en metode for å tilordne DTO tilbake til det opprinnelige objektet. Denne metoden trekker ut dataene fra DTO og fyller ut det opprinnelige objektet.
Følgende eksempel viser hvordan du oppretter og bruker DTOer for serialisering og deserialisering av komplekse objekter:
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
public class Company
{
public string Name { get; set; }
public List<Employee> Employees { get; set; }
// Constructor to initialize the Employees list
public Company(Employee employee)
{
Name = "Contoso Ltd";
Employees = new List<Employee> { employee };
}
}
public class Employee
{
public string Name { get; set; }
public int Age { get; set; }
public string Gender { get; set; }
public string Address { get; set; }
public string Email { get; set; }
public int EmployeeId { get; set; }
public double Salary { get; set; }
public List<Person> Dependents { get; set; }
public List<Person> EmergencyContacts { get; set; }
// Constructor to initialize the lists
public Employee()
{
Dependents = new List<Person>();
EmergencyContacts = new List<Person>();
}
}
public class EmployeeDTO
{
public string Name { get; set; }
public int EmployeeId { get; set; }
}
class Program
{
static void Main()
{
// Create an Employee object
Employee employee = new Employee
{
Name = "Elize Harmsen",
Age = 35,
Gender = "Female",
Address = "123 Main St",
Email = "elize@example.com",
EmployeeId = 101,
Salary = 75000,
Dependents = new List<Person>
{
new Person { Name = "Peter Zammit", Age = 35 }
},
EmergencyContacts = new List<Person>
{
new Person { Name = "Anette Thomsen", Age = 40 }
}
};
// Create a Company object with the Employee
Company company = new Company(employee);
// Map Employee to EmployeeDTO
EmployeeDTO employeeDTO = new EmployeeDTO
{
Name = employee.Name,
EmployeeId = employee.EmployeeId
};
// Serialize EmployeeDTO to JSON
string json = JsonSerializer.Serialize(employeeDTO);
Console.WriteLine("Serialized EmployeeDTO:");
Console.WriteLine(json);
// Deserialize JSON back to EmployeeDTO
EmployeeDTO deserializedEmployeeDTO = JsonSerializer.Deserialize<EmployeeDTO>(json);
// Use the deserialized object to create a new Employee object
Employee newEmployee = new Employee
{
Name = deserializedEmployeeDTO.Name,
EmployeeId = deserializedEmployeeDTO.EmployeeId
};
// Use the newEmployee.EmployeeId to find the original Employee object in the Company
Employee foundEmployee = company.Employees.Find(e => e.EmployeeId == newEmployee.EmployeeId);
if (foundEmployee != null)
{
Console.WriteLine("Found Employee:");
Console.WriteLine($"Name: {foundEmployee.Name}");
Console.WriteLine($"Age: {foundEmployee.Age}");
Console.WriteLine($"Gender: {foundEmployee.Gender}");
Console.WriteLine($"Email: {foundEmployee.Email}");
Console.WriteLine($"EmployeeId: {foundEmployee.EmployeeId}");
Console.WriteLine($"Salary: {foundEmployee.Salary}");
Console.WriteLine($"Dependents: {string.Join(", ", foundEmployee.Dependents.Select(d => d.Name))}");
Console.WriteLine($"Emergency Contacts: {string.Join(", ", foundEmployee.EmergencyContacts.Select(ec => ec.Name))}");
}
else
{
Console.WriteLine("Employee not found in the company.");
}
}
}
I dette eksemplet EmployeeDTO opprettes klassen for å representere en forenklet versjon av Employee klassen. Klassen EmployeeDTO inneholder bare egenskapene som kreves for serialisering. Klassen Employee inneholder flere egenskaper som ikke er inkludert i DTO. Klassen Company inneholder en liste over Employee objekter. Metoden Main demonstrerer hvordan du oppretter et Employee objekt, tilordner det til EmployeeDTO, serialiserer DTO til JSON og deserialiserer det tilbake til DTO. Til slutt viser den hvordan du finner det opprinnelige Employee objektet i Company den deserialiserte DTO-en.
Med denne fremgangsmåten kan du kontrollere serialiseringsprosessen og unngå problemer med komplekse objektgrafer. Ved hjelp av DTOer kan du forenkle datastrukturen og sikre at bare de nødvendige egenskapene er inkludert i de serialiserte utdataene.
Sammendrag
I denne enheten lærte du hvordan du administrerer serialisering og deserialisering av komplekse objekter ved hjelp av JsonSerializerOptions klasse- og dataoverføringsobjekter (DTOer). Klassen JsonSerializerOptions inneholder ulike egenskaper som kan tilpasses for å håndtere komplekse objekter, for eksempel MaxDepth, ReferenceHandlerog Converters. Egenskapen ReferenceHandler er spesielt nyttig for håndtering av sirkelreferanser i komplekse objekter. DTOer er mellomliggende objekter som forenkler overføringen av data mellom ulike lag i et program, slik at du kan kontrollere hvilke egenskaper som er inkludert i de serialiserte utdataene. Ved å utnytte disse teknikkene kan du oppnå mer pålitelig og effektiv serialisering og deserialisering av komplekse JSON-data, noe som gjør det enklere å arbeide med og integrere i programmene dine.