Изменяет ли размер структуры нарушение в С#?
Просто любопытно, меняет ли размер типа struct/value разрывное изменение в С#? Структуры, как правило, более чувствительны в плане памяти, так как их изменение напрямую влияет на размер массивов/других структур. Существуют ли какие-либо примеры кода, который разбивается, как двоично-мудрый, так и исходный, после изменения структуры структуры в используемой библиотеке?
ПРИМЕЧАНИЕ. Под "breaks" я подразумеваю, что он вообще не компилируется, или IL недействителен. Так, например, я бы не стал рассматривать это нарушение:
// My.Library v1
public struct MyStruct {}
// My.Library v2
public struct MyStruct { int _field; }
// App code
using My.Library;
using System.Runtime.InteropServices;
Console.WriteLine(Marshal.SizeOf<MyStruct>()); // before printed 1, now prints 4
поскольку он все еще работает.
Ответы
Ответ 1
Изменение размера путем добавления полей в порядке для строго управляемого кода.
Добавление полей (ов) не является изменением, поскольку код будет перезаписываться с новым типом, и все распределения будут использовать правильный размер. Так как это тип значения, новые поля будут правильно инициализированы пустым значением.
Удаление/изменение типов существующих полей или свойств определенно нарушает изменения.
Типы значений запечатаны, поэтому другие типы библиотек не могут быть получены из этого типа - поэтому в отличие от классов они не могут создавать проблемы с "этот производный класс не реализовал новый метод виртуального свойства/интерфейса".
Примечание: если тип значения используется для взаимодействия или любого другого типа двоичной сериализации вне вашего контроля, чем любое нарушение прерывается.
т.е. кто-то использовал MyLib.Point {int x;int y;}
для сохранения списка точек с двоичной сериализацией в файл. Если теперь "MyLib" добавляет новое поле в MyLib.Point
, чем сериализованные данные больше не могут быть прочитаны с помощью двоичной сериализации. Аналогичная проблема с встроенным взаимодействием.
Ответ 2
Да, несовместимость исходного кода, безусловно, возможна даже в строго управляемом коде, если вы добавите новое поле. Взяв ваш пример, он компилируется с версией 1, но не с версией 2:
MyStruct s;
Console.WriteLine(s);
Причина в том, что С# позволяет использовать struct local, если всем полям присвоены значения. В версии 1 нет полей, поэтому s
"определенно назначается". Однако, если поле добавлено в версии 2, даже если оно является приватным, то это больше не компилируется, потому что s
больше не определенно назначается.
Этот случай должен быть двоичным, поскольку CLR гарантирует инициализацию полей их значениями по умолчанию.
У Джареда Парсонса был хороший пост в блоге по теме частных полей в структурах, где он описывает другие случаи, когда изменение частных деталей реализации было бы опасным (для небезопасного кода) или взлома.