Gå til indholdet

Serialisering

Serialisering er processen, hvor datastrukturen eller objektets tilstand konverteres til en format, der kan gemmes eller overføres og gendannes senere. Deserialisering er den modsatte process.

Information til undervisere

Nogen gange bruges klasser blot til serialisering - eksempelvis fra json til objekt og retur igen, og det er vigtigt at forstå at det er en mulighed.

I C# er der forskellige måder at gøre dette på, og for at illustrere eksemplerne vil der blive brugt en Person-klasse med to egenskaber: Navn (string) og Alder (int).

[Serializable]
public class Person
{
    public string Navn { get; set; }
    public int Alder { get; set; }
}

JSON-serialisering

JSON, der står for JavaScript Object Notation, er et letvægts dataudvekslingsformat, der er nemt for mennesker at læse og skrive, og samtidig let for maskiner at parse og generere. JSON er et tekstformat, der er fuldstændig sprog-agnostisk, men det bruger konventioner, der er kendt fra programmeringssprog som C, C++, C#, Java, JavaScript, Perl, Python og mange andre. Disse egenskaber gør JSON til et ideelt dataudvekslingsformat.

Info

I Viual Studio kan du nemt skabe klasser fra JSON ved at kopiere JSON til udklipsholderen og vælge Edit -> Paste Special -> Paste JSON as Classes.

JSON-formatet understøtter to typer af datastrukturer:

  1. Samling af nøgle-værdi par: I forskellige sprog er dette realiseret som objekter, poster, strukturer, ordbøger, hash-tabeller, keyed lists, eller associative arrays. I JSON repræsenteres disse strukturer i det, der kaldes et “JSON-objekt”, der er en samling af nøgle-værdi-par, omgivet af krøllede parenteser {}. Nøglerne skal være strenge, og hver nøgle-værdi-par adskilles af et kolon :.

    Eksempel på et JSON-objekt:

    {
        "name": "John Doe",
        "age": 30,
        "isEmployed": true
    }
    
  2. Lister af værdier: I forskellige sprog, er dette realiseret som arrays, vektorer, lister, eller sekvenser. I JSON repræsenteres disse som “JSON-arrays”, der er en ordnet liste af værdier, omgivet af firkantede parenteser [].

    Eksempel på et JSON-array:

    [1, 2, 3, 4, 5]
    

JSON understøtter flere datatyper, herunder tal, strenge, boolske værdier (true/false), arrays, objekter, og null. Bemærk dog, at JSON ikke har et specifikt format for datoer, hvilket er en af de udfordringer, man ofte støder på, når man arbejder med JSON.

Den brede understøttelse og læsbarhed af JSON gør det til et udbredt format til at strukturere data, specielt inden for webudvikling og databaser. Mange programmeringssprog har indbyggede værktøjer til at parse og generere JSON-data, hvilket gør det let at arbejde med på tværs af forskellige teknologier og platforme.

Tip

Der findes masser af værktøjer der kan hjælpe med konvertering af JSON til C# kode. En af de alle bedste er quicktype.io, som også findes som en VS og VSC extension.

System.Text.Json

System.Text.Json er et moderne og hurtigt JSON-bibliotek inkluderet i .NET Core 3.0 og nyere. Det tilbyder en enkel og effektiv måde at arbejde med JSON-data.

Serialisering:

using System.Text.Json;

var person = new Person { Navn = "Lene", Alder = 30 };
string jsonString = JsonSerializer.Serialize(person);

Deserialisering:

using System.Text.Json;

string jsonString = "{\"Navn\":\"Lene\",\"Alder\":30}";
var person = JsonSerializer.Deserialize<Person>(jsonString);

Newtonsoft.Json

Newtonsoft.Json (også kendt som Json.NET) er et populært tredjepartsbibliotek til arbejde med JSON i .NET. Det har eksisteret længere end System.Text.Json og tilbyder flere funktioner og fleksibilitet.

Serialisering:

using Newtonsoft.Json;

var person = new Person { Navn = "Lene", Alder = 30 };
string jsonString = JsonConvert.SerializeObject(person);

Deserialisering:

using Newtonsoft.Json;

string jsonString = "{\"Navn\":\"Lene\",\"Alder\":30}";
var person = JsonConvert.DeserializeObject<Person>(jsonString);

XML-serialisering

XML, der står for eXtensible Markup Language, er et mærkesprog, der er designet til at strukturere, lagre og transportere data. XML er meget brugbart i mange forskellige it-kontekster, da det tillader at data kan deles mellem forskellige systemer – uafhængigt af deres indbyggede teknologi.

Info

I Viual Studio kan du nemt skabe klasser fra XML ved at kopiere XML til udklipsholderen og vælge Edit -> Paste Special -> Paste XML as Classes.

XML-data er kendt for sin træ-lignende struktur, der er let at læse og skrive for mennesker, samtidig med at det er let at parse og generere for maskiner. Her er et eksempel på en XML-dokument:

<person>
    <name>John Doe</name>
    <age>30</age>
    <isEmployed>true</isEmployed>
</person>

XML bruger start- og slut-tags til at definerer elementer. I ovenstående eksempel er <person>, <name>, <age> og <isEmployed> alle elementer i XML-dokumentet. Hvert element kan have tekstindhold og attributter.

XML kan være understøttet med dataintegritet via skemaer. Et XML-skema er en definition, der dikterer strukturen af et XML-dokument, herunder hvilke elementer og attributter der kan optræde, deres datatyper, og deres hierarki.

Endnu en central egenskab ved XML er dens platformuafhængighed. Dette gør det til et ideelt format for dataudveksling, da det kan læses af forskellige typer af applikationer (for eksempel, både web og desktop applikationer).

Selvom XML er meget kraftfuldt, kan det også være mere tungt i forhold til alternative formater som JSON, specielt for store mængder data. Dette er vigtigt at overveje, når man vælger det mest passende format til en given opgave.

For at arbejde med XML i C# kan man bruge XmlSerializer-klassen, der findes i System.Xml.Serialization-namespace.

Serialisering:

using System.IO;
using System.Xml.Serialization;

var person = new Person { Navn = "Lene", Alder = 30 };
XmlSerializer serializer = new XmlSerializer(typeof(Person));

using (StringWriter stringWriter = new StringWriter())
{
    serializer.Serialize(stringWriter, person);
    string xmlString = stringWriter.ToString();
}

Deserialisering:

using System.IO;
using System.Xml.Serialization;

string xmlString = "<Person><Navn>Lene</Navn><Alder>30</Alder></Person>";
XmlSerializer serializer = new XmlSerializer(typeof(Person));

using (StringReader stringReader = new StringReader(xmlString))
{
    var person = (Person)serializer.Deserialize(stringReader);
}

Opgaver

Binary Serialization

Binary serialisering konverterer objekter til en binær repræsentation, der kan lagres eller overføres mellem systemer. I .NET kan man bruge BinaryFormatter-klassen til at serialisere og deserialisere objekter i binære formater.

Serialisering:

using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

var person = new Person { Navn = "Lene", Alder = 30 };
BinaryFormatter formatter = new BinaryFormatter();

using (MemoryStream memoryStream = new MemoryStream())
{
    formatter.Serialize(memoryStream, person);
    byte[] binaryData = memoryStream.ToArray();
    string filePath = @"c:\temp\output.bin";
    File.WriteAllBytes(filePath, binaryData);
}

Deserialisering:

using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
string filePath = @"c:\temp\output.bin";
byte[] binaryData = File.ReadAllBytes(filePath);
BinaryFormatter formatter = new BinaryFormatter();

using (MemoryStream memoryStream = new MemoryStream(binaryData))
{
    var person = (Person)formatter.Deserialize(memoryStream);
}

YAML Serialization

YAML er et menneskelæsbart data-serialiseringsformat, der er let at læse og skrive. Der er flere .NET-biblioteker tilgængelige for at arbejde med YAML, såsom YamlDotNet.

Serialisering:

using YamlDotNet.Serialization;

var person = new Person { Navn = "Lene", Alder = 30 };
var serializer = new SerializerBuilder().Build();
string yamlString = serializer.Serialize(person);
Console.WriteLine(yamlString);

Deserialisering:

using YamlDotNet.Serialization;

string yamlString = "Navn: Lene\nAlder: 30\n";
var deserializer = new DeserializerBuilder().Build();
var person = deserializer.Deserialize<Person>(yamlString);

MessagePack Serialization

MessagePack er et binært serialiseringsformat, der er både hurtigt og kompakt. Der er et officielt .NET-bibliotek kaldet MessagePack for C#, der gør det nemt at arbejde med MessagePack-formatet i .NET.

Serialisering:

using MessagePack;

var person = new Person { Navn = "Lene", Alder = 30 };
byte[] messagePackData = MessagePackSerializer.Serialize(person);
string filePath = @"c:\temp\output.bin";
File.WriteAllBytes(filePath, messagePackData);

Deserialisering:

using MessagePack;

string filePath = @"c:\temp\output.bin";
byte[] messagePackData = File.ReadAllBytes(filePath);
var person = MessagePackSerializer.Deserialize<Person>(messagePackData);

CSV Serialization

CSV er et simpelt og udbredt format til lagring af tabeldata. Man kan bruge biblioteker som CsvHelper til at læse og skrive CSV-filer i .NET.

Serialisering:

using CsvHelper;
using System.Globalization;
using System.IO;

var person = new Person { Navn = "Lene", Alder = 30 };
using (var stringWriter = new StringWriter())
using (var csvWriter = new CsvWriter(stringWriter, CultureInfo.InvariantCulture))
{
    csvWriter.WriteHeader<Person>();
    csvWriter.NextRecord();
    csvWriter.WriteRecord(person);
    csvWriter.NextRecord();
    string csvString = stringWriter.ToString();
}

Deserialisering:

using CsvHelper;
using System.Globalization;
using System.IO;

string csvString = "Navn,Alder\r\nLene,30\r\n";
using (var stringReader = new StringReader(csvString))
using (var csvReader = new CsvReader(stringReader, CultureInfo.InvariantCulture))
{
    var person = csvReader.GetRecords<Person>().FirstOrDefault();
}

Validering

Validering af data i C# kan udføres på flere måder for at sikre, at objekter opfylder bestemte kriterier eller forretningsregler. En effektiv tilgang til at indføre validering er direkte i egenskabers set-metoder. Denne metode giver mulighed for at validere input, før det bliver en del af objektets tilstand, og dermed sikre, at objektet altid forbliver i et gyldigt tilstand.

Eksempel på Validering i Set-metoden

public class Person
{
    private string _name;
    public string Name
    {
        get {
            return _name;
        } 
        set
        {
            if (string.IsNullOrWhiteSpace(value))
            {
                throw new ArgumentException("Navn må ikke være tomt", nameof(Name));
            }
            _name = value;
        }
    }

    private int _age;
    public int Age
    {
        get {
            return _age;
        }
        set
        {
            if (value < 0 || value > 130)
            {
                throw new ArgumentOutOfRangeException(nameof(Age), "Alder skal være mellem 0 og 130.");
            }
            _age = value;
        }
    }
}

I dette eksempel kastes en undtagelse, hvis de givne værdier til Name eller Age ikke opfylder de definerede kriterier. Dette sikrer, at Person-objekter altid har gyldige navne og aldre.

Andre Metoder til Validering

Ud over direkte validering i set-metoderne, er der flere andre tilgange til validering af data i C#:

  • Data Annotations: Ofte brugt sammen med Entity Framework eller ASP.NET MVC / Web API, tillader deklarative valideringsregler via attributter placeret oven på klasseegenskaber.
  • Fluent Validation: Et bibliotek, der giver en rig, kædebar API til konfiguration af komplekse valideringsregler i en separat klasse snarere end direkte i domænemodeller.
  • Brugerdefinerede Valideringsmetoder: Metoder inden i klassen, der kan kaldes efter instansiering eller deserialisering for at validere objektets tilstand.
  • Validering ved Deserialisering: Når objekter oprettes fra JSON eller XML, kan brugerdefinerede deserialisatorer inkludere valideringslogik for at sikre, at indkommende data opfylder forventede kriterier, før de konverteres til objekter.

Valg af valideringsmetode afhænger af den specifikke anvendelsessituation, herunder krav til fleksibilitet, genbrugelighed og kompleksitet af valideringslogikken. Mens direkte validering i set-metoder tilbyder enkelhed og umiddelbar feedback, kan mere avancerede scenarier drage fordel af de ekstra funktioner og den organisatoriske klarhed, som biblioteker som Fluent Validation eller indbyggede funktioner som Data Annotations tilbyder.

Brug af Serializable-attributten

Mange moderne serialiseringsbiblioteker i C# ikke kræver [Serializable]-attributten for at kunne serialisere og deserialisere objekter. Nogle populære serialiseringsbiblioteker som Newtonsoft.Json og System.Text.Json fungerer uden denne attribut.

[Serializable]-attributten blev introduceret i .NET Framework og var primært rettet mod binær og SOAP-serialisering ved hjælp af klasserne BinaryFormatter og SoapFormatter. Disse klasser krævede, at [Serializable]-attributten blev brugt på klasser, som skulle serialiseres.

I dag kan man stadig støde på nogle serialiseringsbiblioteker eller -scenarier, der kræver [Serializable]-attributten. At inkludere denne attribut kan derfor øge kompatibiliteten med forskellige serialiseringsbiblioteker og -metoder.

Her er nogle grunde til at overveje at bruge [Serializable]-attributten:

  1. Kompatibilitet: Hvis du vil sikre, at din klasse er kompatibel med forskellige serialiseringsmetoder, kan det være en god idé at inkludere [Serializable]-attributten.

  2. Eksplicit hensigt: Ved at bruge [Serializable]-attributten signalerer du eksplicit, at klassen er beregnet til at blive serialiseret. Dette kan gøre det lettere for andre udviklere at forstå dit kodeformål og hjælpe med vedligeholdelse.

  3. Versionering og vedligeholdelse: Hvis din kode skal være kompatibel med ældre .NET-versioner eller serialiseringsmetoder, der kræver [Serializable]-attributten, kan det være nødvendigt at inkludere den for at undgå problemer.

Det er dog vigtigt at bemærke, at [Serializable]-attributten ikke er nødvendig for mange moderne serialiseringsbiblioteker, og det kan være tilstrækkeligt at undlade den, hvis du kun bruger sådanne biblioteker.