Объединение в C# с неправильно выровненной строкой

У меняошибка" Неправильно выровнено или перекрыто необъектным полем " со следующим кодом.

public struct TypeA
{
   public string A1;
   public string A2;
}
public struct TypeB
{
   public string B1,
   public string B2;
}

Я реализовал объединение, используя System.Runtime.InteropServices с LayoutKind.Explicit

[StructLayout(LayoutKind.Explicit)]
public struct TypeAorB
{
   [FieldOffset(0)]
   public TypeA aa;

   [FieldOffset(0)]
   public TypeB bb;
}

Я думаю, что проблема исходит от строки в структуре. Как мне преодолеть эту проблему?

2 ответа

Решение

То, что вы пытаетесь сделать, не законно. Строка является ссылочным типом и не может перекрываться чем-либо еще в объединении. Это очень важно для сборщика мусора, он не может достоверно определить, какая ссылка хранится в поле, поэтому он не может надежно определить, нужно ли поддерживать строковый объект в действии.

В ваших структурах странно то, что вы перекрываете строку со строкой. Что бы технически работало, нет причин для путаницы сборщика мусора, поскольку он всегда видит действительную ссылку на объект. Но это на самом деле не обрабатывает этот особый случай, Microsoft не написала достаточно кода или не пыталась записать циклы процессора, чтобы проверить идентичность типа.

И это по уважительной причине, потому что вам не нужно перекрывать их в своем заявлении. Microsoft не имеет смысла писать специальный код, который распознает перекрытие, когда вы можете просто избежать этого.

И это черепахи в вашем примере, каждое поле объединения одинаково. Так что нет никакого смысла в использовании союза.

Так что не надо.

Почему смещения поля одинаковы? Они должны быть 0 и 0+[размер TypeA].

Тип A равен 8 байтам, поскольку у вас есть 2x строки, и каждая из них будет использовать 4-байтовый указатель.

Следовательно...

    [StructLayout(LayoutKind.Explicit)]
    public struct TypeAorB
    {
        [FieldOffset(0)]
        public TypeA aa;

        [FieldOffset(8)]
        public TypeB bb;
    }

Если бы вы снова добавили третье поле типа B, вам нужно сделать:

    [StructLayout(LayoutKind.Explicit)]
    public struct TypeAorB
    {
        [FieldOffset(0)]
        public TypeA aa;

        [FieldOffset(8)]
        public TypeB bb;

        [FieldOffset(16)]
        public TypeB bb;
    }
Другие вопросы по тегам