Здравствуйте.
Постепенно пробую использовать подход null reference type в своих проектах, но пока что очень непривычно.
Вот еще одно сомнение меня застало врасплох.
Моя логическая цепочка рассуждений изложена ниже, чувствую, что что-то в ней не так, но что именно не могу понять.
предположим, что значения по умолчанию я не могу использовать. Итак:
1. когда мы объявляем класс, то обязаны разметить символом ? те поля и свойства, которые могут принимать null, типы без ? принимать null не могут.
2. поскольку у нас есть поля без ?, то они должны быть инициализированы при создании класса: либо значение по умолчанию, либо через конструктор.
больше никак?
3. ну и при создании экземпляра мы должны
только через конструктор передать начальные значения. соответственно, весь код, который у нас раньше присваивал значения полям в стиле
oldClass c = new oldClass();
c.field1 = "val1";
c.field2 = "val2";
или
oldClass x = new oldClass { field1 = "val1", field2 = "val2" };
Больше не прокатит.
Вот тут мне бы хотелось услышать экспертов в этом вопросе. все ли я правильно понимаю до этого момента?
А теперь еще один пример.
Допустим я сериализовал экземпляр класса в json, а потом мне нужно его десериализовать.
И я использую Newtonsoft.Json (13.0.1)
Конструктор - это метод и у него там логика присваивания полей может быть разной, во всяком случае, код десериализатора вряд ли будет задумываться о семантике конструктора. А раз так, то возникает опасения, как десериализатор сможет правильно передать значения через конструктор, чтобы правильно восстановить поля исходного класса.
Я провел эксперимент и оказалось, что опасения подтвердились.
исходный код тут:
https://gitlab.com/p6928/nullable-reference-types
у нас есть класс, у которого в конструкторе входные параметры передаются не в том же порядке, в котором объявлены свойства класса.
public class notnullableclass
{
public notnullableclass(string notnull1, string notnull2)
{
this.notnull1 = notnull2;//специально так, чтобы запутать десериализатор
this.notnull2 = notnull1;
}
public string notnull1 { get; set; }
public string notnull2 { get; set; }
}
Код сериализации и десериализации:
notnullableclass e1 = new notnullableclass("init1","init2");
string data1 = JsonConvert.SerializeObject(e1);
Console.WriteLine($"e1: notnull1:{e1.notnull1}; notnull2:{e1.notnull2}");
Console.WriteLine($"data1: {data1}");
notnullableclass e2 = JsonConvert.DeserializeObject<notnullableclass>(data1);
Console.WriteLine($"deserialized e2: notnull1:{e2.notnull1}; notnull2:{e2.notnull2}");
string data2 = "{\"notnull1\":\"init1\",\"notnull2\":\"init2\"}";
Console.WriteLine($"data2: {data2}");
notnullableclass e3 = JsonConvert.DeserializeObject<notnullableclass>(data2);
Console.WriteLine($"deserialized e3: notnull1:{e3.notnull1}; notnull2:{e3.notnull2}");
вывод в консоль:
e1: notnull1:init2; notnull2:init1
data1: {"notnull1":"init2","notnull2":"init1"}
deserialized e2: notnull1:init1; notnull2:init2
data2: {"notnull1":"init1","notnull2":"init2"}
deserialized e3: notnull1:init2; notnull2:init1
как видим, после десериализации значения полей перепутались.
Ну и как после того доверять десериализации null reference types?
А если серьезно, то как все же гарантировать правильную работу кода при применении похода null reference type?
Можно ли все таки гарантировать что поле не будет равно null и при этом не пользоваться конструктором?
Спасибо за внимание.