C++ объединение в C#
Я перевожу библиотеку, написанную на C++, на C#, и ключевое слово 'union' существует один раз. В структуре.
Как правильно перевести его на C#? И что это делает? Это выглядит примерно так;
struct Foo {
float bar;
union {
int killroy;
float fubar;
} as;
}
7 ответов
Вы можете использовать явные макеты полей для этого:
[StructLayout(LayoutKind.Explicit)]
public struct SampleUnion
{
[FieldOffset(0)] public float bar;
[FieldOffset(4)] public int killroy;
[FieldOffset(4)] public float fubar;
}
Непроверенные. Идея состоит в том, что две переменные имеют одинаковую позицию в вашей структуре. Конечно, вы можете использовать только один из них.
Больше информации о профсоюзах в руководстве по структуре
Вы не можете действительно решить, как бороться с этим, не зная кое-что о том, как это используется. Если он просто используется для экономии места, то вы можете игнорировать его и просто использовать структуру.
Однако это обычно не то, почему профсоюзы используются. Есть две распространенные причины их использования. Одним из них является предоставление 2 или более способов доступа к одним и тем же данным. Например, объединение int и массива из 4 байтов - это один (из многих) способов выделить байты 32-битного целого числа.
Другой случай, когда данные в структуре поступили из внешнего источника, такого как сетевой пакет данных. Обычно одним из элементов структуры, содержащей объединение, является идентификатор, который сообщает вам, какой тип объединения действует.
Ни в одном из этих случаев вы не можете слепо игнорировать объединение и преобразовывать его в структуру, в которой два (или более) поля не совпадают.
В C/C++ объединение используется для наложения разных элементов в одном и том же месте памяти, поэтому, если у вас есть объединение int и float, они оба используют одни и те же 4 байта памяти для хранения, очевидно, что запись в один искажает другой (так как int и float имеют разную разметку).
В.Net Microsoft пошла с более безопасным выбором и не включила эту функцию.
РЕДАКТИРОВАТЬ: за исключением взаимодействия
Если вы используете union
чтобы сопоставить байты одного из типов с другим, то в C# вы можете использовать BitConverter
вместо.
float fubar = 125f;
int killroy = BitConverter.ToInt32(BitConverter.GetBytes(fubar), 0);
или же;
int killroy = 125;
float fubar = BitConverter.ToSingle(BitConverter.GetBytes(killroy), 0);
Лично я бы игнорировал UNION все вместе и реализовал бы Killroy и Fubar как отдельные поля
public struct Foo
{
float bar;
int Kilroy;
float Fubar;
}
Использование UNION экономит 32 бита памяти, выделенной int.... не собирается создавать или ломать приложение в наши дни.
Вы можете написать простую оболочку, но в большинстве случаев просто используйте объект, это менее запутанно.
public class MyUnion
{
private object _id;
public T GetValue<T>() => (T)_id;
public void SetValue<T>(T value) => _id = value;
}
public class Foo
{
public float bar;
public int killroy;
public float fubar
{
get{ return (float)killroy;}
set{ killroy = (int)value;}
}
}