Chapter142:HowtouseC#Structsto createaUniontype(SimilartoCUnions)
- 11/06/2024
- C# Programming
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 postsRecent Posts
- Chapter153:C#Script 22/06/2024
- Chapter 152: Unsafe Code in.NET 21/06/2024
- Chapter151:ASP.NETIdentity 20/06/2024