Guid десериализуется в пустое значение c#

Вот условный код:

internal class Program
{
    static void Main(string[] args)
    {
        var groups = new List<Group>();
        var students = new List<Student>();

        for (int i = 0; i < 10; i++)
        {
            groups.Add(new Group());
        }

        for (int i = 0; i < 300; i++)
        {
            var group = groups[new Random().Next(0, groups.Count)];
            students.Add(new Student($"Student {i}", new Random().Next(0, 100), group));
        }

        var xmlFormatter = new XmlSerializer(typeof(List<Student>));

        using (var file = new FileStream("studentsXML.xml", FileMode.Create, FileAccess.Write))
        {
            xmlFormatter.Serialize(file, students);
        }

        using (var file = new FileStream("studentsXML.xml", FileMode.Open))
        {
            var newStudents = xmlFormatter.Deserialize(file) as List<Student>;
            newStudents!.ForEach(s => Console.WriteLine(s));
        }

        Console.WriteLine("__________________________________________________\n");
        Console.WriteLine(students[^1]);
    }
}

[Serializable]
public class Student 
{
    public Guid GuidId { get; }
    public string Name { get; set; }
    public int Age { get; set; }
    public Group Group { get; set; }

    public Student()
    {
        GuidId = new Guid();
        Name = string.Empty;
        Age = default;
        Group = new Group();
    }

    public Student(string name, int age, Group group)
    {
        if (string.IsNullOrWhiteSpace(name))
        {
            throw new ArgumentNullException(nameof(name));
        }

        if (age < 0 || age > 130)
        {
            throw new ArgumentOutOfRangeException(nameof(age));
        }

        Name = name;
        Age = age;
        Group = group;
        GuidId = Guid.NewGuid();
    }

    public override string ToString()
    {
        return $"{GuidId} | {Name} | {Age} | Group: [ {Group} ]";
    }
}

[Serializable]
public class Group
{
    public int Number { get; set; }
    public string Name { get; set; }

    public Group()
    {
        var rnd = new Random();
        Number = rnd.Next(1, 100);
        Name = $"Group {Number}";
    }

    public Group(int number, string name)
    {
        Number = number;
        Name = name;
    }

    public override string ToString()
    {
        return $"Number: {Number}, Name: {Name}";
    }
}

Как я понял, тип Guid сериализуется не правильно (или десериализуется), потому что на выходе в консоле у меня пустое значение Guid. Result

Почему так происходит? И еще вопрос, почему для сериализации определенного типа необходимо, чтобы у этого типа обязательно был конструктор без параметров?


Ответы (1 шт):

Автор решения: Boronnikov Andrey

Сериализация - это процесс "сохранения" данных программы в текстовый формат. Десериализация - это процесс извлечения данных из какого-то условно текстового формата с переносом в исполняемый код. Это может быть xml как у тебя, так и json или вообще бинарный файлик.

Логика такая, что в процессе сериализации система смотрит что у тебя там за объекты, какие поля и переменные у него имеются и записывает в текстовый формат. Типа твоего xml.

А при десериализации сначала создаётся пустой объект без данных - для этого и нужен конструктор без параметров. В процессе система пытается самостоятельно создать пустой экземпляр класса, но она сама по себе "тупая" и не может догадаться что куда пихать в конструктор. (Это ответ на то, для чего нужен конструктор без параметров) И вот после создания пустого экземпляра класса система начинает заполнять поля и переменные в нём. И тут как раз возникает проблема. GuidId у тебя имеет только get;, без set; То есть он записывается при сериализации, но не может задаться в процессе десериализации.

Так что либо добавь set;

public Guid GuidId { get; set; }

Либо, если тебе нужна защита этого поля - сделай приватную сериализуемую переменную и через неё осуществляй запись.

→ Ссылка