C# Language
C # Structs를 사용하여 Union 형식을 만드는 방법 (C 유니온과 유사)
수색…
비고
연합 유형은 여러 언어, 특히 C 언어로 사용되어 동일한 메모리 공간에서 "중첩"할 수있는 여러 유형을 포함합니다. 즉, 길이와 유형이 다른 경우에도 동일한 메모리 오프셋에서 시작하는 서로 다른 필드를 포함 할 수 있습니다. 이것은 메모리를 절약하고 자동 변환을 수행하는 이점이 있습니다.
Struct의 생성자에 주석을 적어 두십시오. 필드가 초기화되는 순서는 매우 중요합니다. 먼저 다른 모든 필드를 초기화 한 다음 마지막 문으로 변경하려는 값을 설정하려고합니다. 필드가 겹치기 때문에 마지막 값 설정은 중요한 값입니다.
C #의 C 스타일 유니온
연합 유형은 C 언어와 같은 여러 언어로 사용되어 "중첩"할 수있는 여러 유형을 포함합니다. 즉, 길이와 유형이 다른 경우에도 동일한 메모리 오프셋에서 시작하는 서로 다른 필드를 포함 할 수 있습니다. 이것은 메모리를 절약하고 자동 변환을 수행하는 이점이 있습니다. 예를 들어 IP 주소를 생각해보십시오. 내부적으로 IP 주소는 정수로 표시되지만 때때로 Byte1.Byte2.Byte3.Byte4와 같이 다른 Byte 구성 요소에 액세스하려고합니다. 이것은 Int32 또는 long과 같은 프리미티브 또는 자신을 정의하는 다른 구조체에 해당하는 모든 값 유형에 적용됩니다.
Explicit Layout Structs를 사용하여 C #에서 동일한 효과를 얻을 수 있습니다.
using System;
using System.Runtime.InteropServices;
// The struct needs to be annotated as "Explicit Layout"
[StructLayout(LayoutKind.Explicit)]
struct IpAddress
{
// The "FieldOffset" means that this Integer starts, an offset in bytes.
// sizeof(int) 4, sizeof(byte) = 1
[FieldOffset(0)] public int Address;
[FieldOffset(0)] public byte Byte1;
[FieldOffset(1)] public byte Byte2;
[FieldOffset(2)] public byte Byte3;
[FieldOffset(3)] public byte Byte4;
public IpAddress(int address) : this()
{
// When we init the Int, the Bytes will change too.
Address = address;
}
// Now we can use the explicit layout to access the
// bytes separately, without doing any conversion.
public override string ToString() => $"{Byte1}.{Byte2}.{Byte3}.{Byte4}";
}
이 방식으로 Struct을 정의한 후에는 C에서 Union을 사용할 때와 마찬가지로 사용할 수 있습니다. 예를 들어 IP 주소를 Random Integer로 만든 다음 주소의 첫 번째 토큰을 변경하여 '100'으로 수정합니다 'ABCD'에서 '100.BCD'까지 :
var ip = new IpAddress(new Random().Next());
Console.WriteLine($"{ip} = {ip.Address}");
ip.Byte1 = 100;
Console.WriteLine($"{ip} = {ip.Address}");
산출:
75.49.5.32 = 537211211
100.49.5.32 = 537211236
C #의 연합 유형에는 구조 필드도 포함될 수 있습니다.
프리미티브 외에도 C #의 Explicit Layout 구조체 (유니온)에는 다른 Structs도 포함될 수 있습니다. 필드가 참조가 아닌 값 유형 인 경우 Union에 포함될 수 있습니다.
using System;
using System.Runtime.InteropServices;
// The struct needs to be annotated as "Explicit Layout"
[StructLayout(LayoutKind.Explicit)]
struct IpAddress
{
// Same definition of IpAddress, from the example above
}
// Now let's see if we can fit a whole URL into a long
// Let's define a short enum to hold protocols
enum Protocol : short { Http, Https, Ftp, Sftp, Tcp }
// The Service struct will hold the Address, the Port and the Protocol
[StructLayout(LayoutKind.Explicit)]
struct Service
{
[FieldOffset(0)] public IpAddress Address;
[FieldOffset(4)] public ushort Port;
[FieldOffset(6)] public Protocol AppProtocol;
[FieldOffset(0)] public long Payload;
public Service(IpAddress address, ushort port, Protocol protocol)
{
Payload = 0;
Address = address;
Port = port;
AppProtocol = protocol;
}
public Service(long payload)
{
Address = new IpAddress(0);
Port = 80;
AppProtocol = Protocol.Http;
Payload = payload;
}
public Service Copy() => new Service(Payload);
public override string ToString() => $"{AppProtocol}//{Address}:{Port}/";
}
이제 전체 서비스 연합 (Service Union)이 긴 (8 바이트) 크기에 맞는지 확인할 수 있습니다.
var ip = new IpAddress(new Random().Next());
Console.WriteLine($"Size: {Marshal.SizeOf(ip)} bytes. Value: {ip.Address} = {ip}.");
var s1 = new Service(ip, 8080, Protocol.Https);
var s2 = new Service(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}.");