C# StructLayout. Явный вопрос
Я пытаюсь понять, почему второй пример ниже работает без проблем, но первый пример дает мне исключение ниже. Мне кажется, что оба примера должны дать исключение на основе описания. Кто-нибудь может просветить меня?
Необработанное исключение: System.TypeLoadException: Не удалось загрузить тип 'StructTest.OuterType' из сборки 'StructTest, Version=1.0.0.0, Culture= нейтральный, PublicKeyToken=null', поскольку он содержит поле объекта со смещением 0, которое неправильно выровнено или перекрыто необъектным полем.
at StructTest.Program.Main (String [] args) Нажмите любую клавишу для продолжения.,,
Пример 1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace StructTest
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct InnerType
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
char[] buffer;
}
[StructLayout(LayoutKind.Explicit)]
struct OuterType
{
[FieldOffset(0)]
int someValue;
[FieldOffset(0)]
InnerType someOtherValue;
}
class Program
{
static void Main(string[] args)
{
OuterType t = new OuterType();
System.Console.WriteLine(t);
}
}
}
Пример 2
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace StructTest
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct InnerType
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
char[] buffer;
}
[StructLayout(LayoutKind.Explicit)]
struct OuterType
{
[FieldOffset(4)]
private int someValue;
[FieldOffset(0)]
InnerType someOtherValue;
}
class Program
{
static void Main(string[] args)
{
OuterType t = new OuterType();
System.Console.WriteLine(t);
}
}
}
2 ответа
Общеязыковая среда выполнения содержит верификатор, который гарантирует, что работающий код (проверяемый IL) не может повредить память в управляемой среде. Это мешает вам объявить такую структуру, в которой поля перекрываются. По сути, ваша структура содержит два элемента данных. Одно целое число (которое составляет 4 байта) и собственное целое число (размер указателя). На 32-битном CLR, в котором вы, вероятно, выполняете свой код, char[]
займет 4 байта, поэтому, если вы поместите целое число менее чем в четыре байта от начала структуры, у вас будут перекрывающиеся поля. Интересно отметить, что оба ваших фрагмента кода с ошибкой в 64-битной среде выполнения, так как размер указателя составляет 8 байт.
Я решил ответить решением, которое я использовал для создания профсоюза, что и было моим первоначальным намерением. Я использовал небезопасную структуру и фиксированный массив, а затем использовал свойство для взаимодействия с фиксированным массивом. Я считаю, что это должно делать то, что я хочу.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace StructTest
{
[StructLayout(LayoutKind.Explicit)]
unsafe struct OuterType
{
private const int BUFFER_SIZE = 100;
[FieldOffset(0)]
private int transactionType;
[FieldOffset(0)]
private fixed byte writeBuffer[BUFFER_SIZE];
public int TransactionType
{
get { return transactionType; }
set { transactionType = value; }
}
public char[] WriteBuffer
{
set
{
char[] newBuffer = value;
fixed (byte* b = writeBuffer)
{
byte* bptr = b;
for (int i = 0; i < newBuffer.Length; i++)
{
*bptr++ = (byte) newBuffer[i];
}
}
}
get
{
char[] newBuffer = new char[BUFFER_SIZE];
fixed (byte* b = writeBuffer)
{
byte* bptr = b;
for (int i = 0; i < newBuffer.Length; i++)
{
newBuffer[i] = (char) *bptr++;
}
}
return newBuffer;
}
}
}
class Program
{
static void Main(string[] args)
{
OuterType t = new OuterType();
System.Console.WriteLine(t);
}
}
}