Reputation: 31
I'm trying to create union like structure with byte[] field. So next type declaration causes an error in runtime:
[StructLayout(LayoutKind.Explicit)]
public struct Int64ByteArr
{
[FieldOffset(0)]
public UInt64 u64;
[FieldOffset(0)]
public Int64 s64;
[FieldOffset(0), MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] bytes;
}
when calling a function which uses variable of that type, program causes exception with that description:
Необработанное исключение типа "System.TypeLoadException" в System.Windows.Forms.dll Дополнительные сведения: Не удалось загрузить тип "Int64ByteArr" из сборки "ChalengeCalc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", так как он содержит поле объекта со смещением 0, которое неверно выровнено или перекрыто полем, не представляющим объект.
translation to english: unhandled exception of type "System.TypeLoadException" in System.Windows.Forms.dll ) Additional information: Failed to load type "Int64ByteArr" from "ChalengeCalc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" Assembly cause it contains field of object with oaffset 0, which is incorrectly aligned of overflowed by field which not presenting an object
also i try this variant:
[StructLayout(LayoutKind.Sequential)]
public struct ByteArr8
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] bytes;
public Byte this[int idx]
{
get
{
if (idx < 0 || idx > 7) return 0;
return bytes[idx];
}
set
{
if (idx < 0 || idx > 7) return;
bytes[idx] = value;
}
}
}
[StructLayout(LayoutKind.Explicit)]
public struct Int64ByteArr
{
[FieldOffset(0)]
public UInt64 u64;
[FieldOffset(0)]
public Int64 s64;
[FieldOffset(0)]
public ByteArr8 bytes;
}
It hangs with the same exception. So there is a question: "how to?"
Upvotes: 0
Views: 364
Reputation: 9650
In your particular case you may marshal the byte array field only and provide getters/setters for the others:
[StructLayout(LayoutKind.Sequential)]
struct Int64ByteArr
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] bytes;
public UInt64 u64
{
get { return BitConverter.ToUInt64(bytes, 0); }
set { bytes = BitConverter.GetBytes(value); }
}
public Int64 s64
{
get { return BitConverter.ToInt64(bytes, 0); }
set { bytes = BitConverter.GetBytes(value); }
}
}
Note: inspired by David Heffernan's comment to this question.
In general case you would have to use custom marshaling, I believe.
Upvotes: 1