C# StructLayoutAttribute

Как известно, Just InTime компилятор выполняет ряд оптимизаций для повышения быстродействия приложения. Одной из таких оптимизаций является порядок размещения полей типа. Так, CLR может упорядочить поля таким образом, что ссылки на объекты окажутся в одной группе, а поля данных и свойства, выровненные и упакованные, - в другой.

Но порой, такое поведение компилятора может приводить к неожиданным результатам (например при работе с unmanaged кодом). Для избежания "неприятных" ситуаций существуют специальный атрибут при описании классов или структур. Чтобы разрешить CLR устанавливать порядок полей следует указать атрибут System.Runtime.InteropServices.StructLayoutAttribute LayoutKind.Auto, чтобы сохранить порядок, указанный программистом, - LayoutKind.Sequental. По-умолчанию же, компилятор C# LayoutKindAuto для ссылочных типов (классов) и LayoutKindSequental для значимых типов (структур). Однако, если же ваш значимый тип не будет работать с unmanaged кодом, то имеет смысл изменить значение по-умолчанию и
разрешить CLR упорядочить поля:

using System;
using System.Runtime.InteropServices;
// разрешаем CLR упорядочивание полей
[StructLayout(LayoutKind.Auto)]
struct my_Point
{
  int x,y;
}


Кроме того, существует еще один атрибут, предоставляющий интересные возможности. Так, задав атрибут LayoutKind.Explicit, можно явно указывать компилятору смещения тех или иных полей с помощью FieldOffset(Int32) в байтах от начала экземпляра. С помощью данного метода можно добиться эффекта, подобного uninon из Си или Record-Case, Absolute из Паскаля. Например:
 
using System;
using System.Runtime.InteropServices;
// явно зададим смещения полей
[StructLayout(LayoutKind.Explicit)]
struct LikeUninon
{
  [FieldOffset(0)] Int32 X;
  [FieldOffset(0)] Int16 X1;
  [FieldOffset(2)] Int16 X2;
}


Но не следует перекрывать ссылочные поля значимыми и наоборот. Кроме того, все пересекающиеся байты должны быть доступны через открытые(public) поля.