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;}
    }
}
Другие вопросы по тегам