Chapter142:HowtouseC#Structsto createaUniontype(SimilartoCUnions)

No Comments

Section142.1:C-StyleUnionsinC#

Uniontypesareusedinseverallanguages,likeC-language,tocontainseveraldifferenttypeswhichcan”overlap”.In other words, they might contain different fields all of which start at the same memory offset, even when they might have different lengths and types. This has the benefit of both saving memory, and doing automatic conversion.

Think of an IP address, as an example. Internally, an IP address is represented as an integer, but sometimes we wanttoaccessthedifferentBytecomponent,asinByte1.Byte2.Byte3.Byte4.Thisworksforanyvaluetypes,beit primitives like Int32 or long, or for other structs that you define yourself.

WecanachievethesameeffectinC#byusingExplicitLayoutStructs.

usingSystem;

usingSystem.Runtime.InteropServices;

//Thestructneedstobeannotatedas“ExplicitLayout”

[StructLayout(LayoutKind.Explicit)]

structIpAddress

{

//The“FieldOffset”meansthatthisIntegerstarts,anoffsetinbytes.

//sizeof(int)4,sizeof(byte)=1

[FieldOffset(0)]publicintAddress;

[FieldOffset(0)]publicbyteByte1;

[FieldOffset(1)]publicbyteByte2;

[FieldOffset(2)]publicbyteByte3;

[FieldOffset(3)]publicbyteByte4;

publicIpAddress(intaddress):this()

{

//WhenweinittheInt,theByteswillchangetoo.

Address=address;

}

//Nowwecanusetheexplicitlayouttoaccessthe

//bytesseparately,withoutdoinganyconversion.

publicoverridestringToString()=>$”{Byte1}.{Byte2}.{Byte3}.{Byte4}”;

}

Having defined out Struct in this way, we can use it as we would use a Union in C. For example, let’s create an IP addressasaRandomIntegerandthenmodifythefirsttokenintheaddressto’100′,bychangingitfrom’A.B.C.D’to ‘100.B.C.D’:

varip=newIpAddress(newRandom().Next());

Console.WriteLine($”{ip}={ip.Address}”);ip.Byte1=

100;

Console.WriteLine($”{ip}={ip.Address}”);

Output:

75.49.5.32=537211211

100.49.5.32=537211236

ViewDemo

Section142.2:UnionTypesinC#canalsocontainStructfields

Apartfromprimitives,theExplicitLayoutstructs(Unions)inC#,canalsocontainotherStructs.Aslongasafieldisa Value type and not a Reference, it can be contained in a Union:

usingSystem;

usingSystem.Runtime.InteropServices;

//Thestructneedstobeannotatedas“ExplicitLayout”

[StructLayout(LayoutKind.Explicit)]

structIpAddress

{

//SamedefinitionofIpAddress,fromtheexampleabove

}

//Nowlet’sseeifwecanfitawholeURLintoalong

//Let’sdefineashortenumtoholdprotocols

enumProtocol:short{Http,Https,Ftp,Sftp,Tcp}

//TheServicestructwillholdtheAddress,thePortandtheProtocol

[StructLayout(LayoutKind.Explicit)]

structService

{

[FieldOffset(0)]publicIpAddressAddress;

[FieldOffset(4)]publicushortPort;

[FieldOffset(6)]publicProtocolAppProtocol;

[FieldOffset(0)]publiclongPayload;

publicService(IpAddressaddress,ushortport,Protocolprotocol)

{

Payload=0;

Address=address;

Port      =port;

AppProtocol=protocol;

}

publicService(longpayload)

{

Address=newIpAddress(0);

Port=80;

AppProtocol=Protocol.Http;

Payload=payload;

}

publicServiceCopy()=>newService(Payload);

publicoverridestringToString()=>$”{AppProtocol}//{Address}:{Port}/”;

}

WecannowverifythatthewholeServiceUnionfitsintothesizeofalong(8bytes).

varip=newIpAddress(newRandom().Next());

Console.WriteLine($”Size:{Marshal.SizeOf(ip)}bytes.Value:{ip.Address}={ip}.”);

vars1=newService(ip,8080,Protocol.Https);

vars2=newService(s1.Payload);

s2.Address.Byte1=100;

s2.AppProtocol=Protocol.Ftp;

Console.WriteLine($”Size:{Marshal.SizeOf(s1)}bytes.Value:{s1.Address}={s1}.”); Console.WriteLine($”Size: {Marshal.SizeOf(s2)} bytes. Value: {s2.Address} = {s2}.”);

ViewDemo

About us and this blog

We are a digital marketing company with a focus on helping our customers achieve great results across several key areas.

Request a free quote

We offer professional SEO services that help websites increase their organic search score drastically in order to compete for the highest rankings even when it comes to highly competitive keywords.

Subscribe to our newsletter!

More from our blog

See all posts
No Comments

Leave a Comment