BT Akademi'nin değerli eğitmenlerinden Özcan Değirmenci'nin BT Akademi'de verdiği
WinForm 2.0 Akademideki örnekleri incelerken bol bol StructLayout attribute'leri ile karşılaşıyorum . Malum Windows API seviyesinde kod yazmayan geliştiricilerin pek ihtiyaç duymadığı hatta birçoğunun haberi dahi olmadığı ama kontrol geliştiren, ciddi manada detaylı windows uygulamaları geliştirenlerin - örneğin .NET Framework'ün desteklemediği sistem fonksiyonlarının kullanıldığı - sıklıkla kullandığı bu attrribute sayesinde class'ların yada structların - kısaca Type'ların - memory'de istenilen şekilde yerleşmesini sağlayabiliyoruz.
Herhangi bir Type bildirimi yapıldığında CLR performans sağlanması adına bu Type'ın üye elemanlarının memory'deki yerleşim düzenini kendisi ayarlamaktadır. Bu şekilde hem daha az memory kullanımı optimize ediyor hem de ilgili Type'ın üye elemanlarına erişim hızının artırılmasını sağlıyor. Fakat bazı Windows API fonksiyonları bizden parametre olarak özel bir şekilde memory'de dizilmiş struct isteyebiliyor. Bu durumda memory'deki dizilimini CLR'nin değil de bizim yapmamız gerekiyor. İşte burda
StructLayout attribute'ü tüm ihtiyacımızı karşılıyor. LayoutKind numaralandırıcısını (Enumeration) kullanarak dizilimi kendimiz beliryebiliyoruz.
Not : Struct tanımladığınızda otomatik olarak bu özellik Sequential'dir. Ama bu attribute'ü bir class için kullanmak isterseniz mutlaka LayoutKind.Sequential numaralandırıcısını kullanmalısınız.Auto : CLR'nin yaptığı gibi
Sequential : Sıralı bir şekilde aynen bildirimdeki sıraya göre
Explicit : Biz nasıl istiyorsak öyle.
[StructLayout(LayoutKind.Sequential)]
public struct Coord
{
int x;
int y;
}
gibi..Eğer bu dizilimin bizim isteğimize göre olmasını istersek de LayoutKind.Explicit numaralandırıcısını aşağıdaki gibi kullanmalıyız.
[StructLayout(LayoutKind.Explicit)]
struct Coord
{
[FieldOffset(0)]
public int x;
[FieldOffset(4)]
public int y;
}
Üye elemanlarına FieldOffset attribute'ünün uygulandığını görüyoruz. Bu sayede memory'de hangi elemanın hangi offsetten -kaçıncı byte'dan - itibaren yerleşeceğine karar verebiliyoruz. Yukardaki örnekte yapımızın 0. byte'ından itibaren x'in yerleşeceğini, 4.byte'dan itibaren de - sizeof(int) de kullanabilirsiniz. int'in büyüklüğü kadar memoryde ilerlemek için - y'nin yerleştirileceğini belirtebiliyoruz. Bu özellik sayesinde aslında çok az memory kullanarak struct yapımızın içinde çok sayıda üye eleman tanımlayabiliriz. Yapmamız gereken tekşey tüm üye elemanlarımızın 0. offsetten itibaren memory'ye yerleşmelerini sağlamak.
[StructLayout(LayoutKind.Explicit)]
struct Coord
{
[FieldOffset(0)]
public int x;
[FieldOffset(0)]
public int y;
[FieldOffset(0)]
public long z;
}
---- x
---- y
---- ---- z
Bu sayede 8 byte'lık bir alanda 2 int bir de long türünden değişken saklayabiliyoruz ;)
C 'deki union yapısına baya bir benzedi değil mi? Ha dersiniz ki ben gittim z ye 12 değerini atadım sonra gittim x'e 22 değerini atadım z'nin değeri şimdi ne oldu ? Bilmem ne oldu ? :) Aşağıdaki kodu biraz kurcalamakda fayda var.
public class Test
{
static void Main(string[] args)
{
Coord c = new Coord();
c.z = 2000000000;
c.x = 20;
Console.WriteLine(c.z);
}
}
[StructLayout(LayoutKind.Explicit)]
struct Coord
{
[FieldOffset(0)]
public int x;
[FieldOffset(0)]
public int y;
[FieldOffset(0)]
public long z;
}