2016-06-16 50 views
10

Po prostu ciekawy, czy zmiana rozmiaru typu struct/value powoduje zmianę zerwania w C#? Struktury są bardziej wrażliwe pod względem układu pamięci, ponieważ ich zmiana wpływa bezpośrednio na rozmiar tablic/innych struktur. Czy są jakieś przykłady kodu, który łamie się, binarnie lub źródłowo, po zmianie układu struktury w bibliotece, której używa?Czy zmiana rozmiaru struktury jest przełamującą zmianą w C#?

UWAGA: Przez "przerwy" mam na myśli, że w ogóle się nie kompiluje lub IL jest unieważniony. Więc na przykład nie uważam tego za przełomową zmianę:

// 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 

ponieważ nadal działa.

+1

Czy używasz InteropServices do interakcji z niezarządzanym kodem? Jeśli tak, odpowiedź brzmi "tak", jest to przełomowa zmiana. Jeśli nie, odpowiedź jest bardziej zniuansowana. –

+0

Przepraszam, nie rozumiem twojego pytania ... Rekompilowałeś Zgromadzenie, więc wszystko powinno być w porządku? –

+0

Dżin kryje wiele grzechów. Wielkości struktur nie odgrywają żadnej roli w czasie kompilacji, tylko w środowisku wykonawczym. Posiadanie niezainicjowanego pola może być zaskakujące. –

Odpowiedz

8

Zmiana rozmiaru poprzez dodanie pól jest odpowiednia dla ściśle zarządzanego kodu.

Dodanie pól nie jest zmianą łamania, ponieważ kod zostanie ponownie JIT-ed z nowym typem, a wszystkie alokacje użyją poprawnego rozmiaru. Ponieważ jest to typ wartości, nowe pola będą poprawnie zainicjalizowane pustymi wartościami.

Usuwanie/zmiana typów istniejących pól lub właściwości zdecydowanie zmienia zmianę.

Typy wartości są zapieczętowane - więc żadne inne biblioteki nie mogą pochodzić z tego typu - w przeciwieństwie do klas nie mogą tworzyć problemów z "ta klasa pochodna nie implementuje nowej metody wirtualnej właściwości/interfejsu".

Uwaga: jeśli typ wartości jest używany do interopu lub innego rodzaju serializacji binarnej poza kontrolą, niż jakakolwiek zmiana jest zerwana.

tj. ktoś inny użył MyLib.Point {int x;int y;}, aby zapisać listę punktów z serializacją binarną do pliku. Jeśli teraz "MyLib" dodaje nowe pole do MyLib.Point, wówczas dane zserializowane nie będą już mogły być czytane z serializacją binarną. Podobny problem z natywnym współdziałaniem.

3

Tak, niekompatybilności kodu źródłowego są zdecydowanie możliwe, nawet w ściśle zarządzanym kodzie, jeśli dodasz nowe pole. Biorąc przykład ten kompiluje w wersji 1, ale nie w wersji 2:

MyStruct s; 
Console.WriteLine(s); 

Powodem jest to, że C# pozwala struct lokalny być stosowane, jeżeli wszystkie pola zostały przypisane wartości. W wersji 1 nie ma pól, więc s jest "zdecydowanie przypisany". Jednak jeśli pole zostanie dodane w wersji 2, nawet jeśli jest prywatne, to nie będzie już kompilacji, ponieważ s nie jest już definitywnie przypisane.

Ten przypadek powinien być zgodny binarnie, ponieważ CLR gwarantuje inicjalizację pól do ich wartości domyślnych.

Jared Parsons miał good blog post na temat prywatnych pól w strukturach, w których wyszczególnił inne przypadki, w których zmiana prywatnych szczegółów realizacji byłaby niebezpieczna (dla niebezpiecznego kodu) lub zerwania.

+0

Rewizja. Dzięki za post na blogu, była to ciekawa lektura. –