在下面的代码中引发了异常。
'type无法整理,因为嵌入式数组的长度 实例与布局中声明的长度不匹配
我知道是因为字符串和char数组的长度不匹配,所以我试图用空白字符固定字符串的长度。
要添加空白字符,我应该知道RUNTIME中目标char数组的长度,但我不能知道,因为char数组成员还为null。
如何获取char数组的长度?有没有比我更好的方法了?
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct TestStruct
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] public char[] CharArray;
}
private void Button1_Click(object sender, RoutedEventArgs e)
{
var _TestStruct = new TestStruct();
var _IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(_TestStruct));
var _String = "a";
_TestStruct.CharArray = _String.ToCharArray();
Marshal.StructureToPtr(_TestStruct, _IntPtr, false); // ERROR
// void TestFunction(IntPtr _Intptr);
Marshal.FreeHGlobal(_IntPtr);
}
答案 0 :(得分:1)
如果将5定义为常量,则可以将char数组填充为零,以使其填充所需的大小:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct TestStruct
{
public const int CharArraySize = 5;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = CharArraySize)] public char[] CharArray;
}
private void Button1_Click(object sender, RoutedEventArgs e)
{
TestStruct _TestStruct = new TestStruct();
IntPtr _IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(_TestStruct));
string _String = "a";
_TestStruct.CharArray = _String.ToCharArray();
if (_TestStruct.CharArray.Length < TestStruct.CharArraySize)
_TestStruct.CharArray = _TestStruct.CharArray.Concat(Enumerable.Repeat((char)0, TestStruct.CharArraySize - _TestStruct.CharArray.Length)).ToArray();
Marshal.StructureToPtr(_TestStruct, _IntPtr, false); // This works now
// void TestFunction(IntPtr _Intptr);
Marshal.FreeHGlobal(_IntPtr);
}
您可以使用反射使此过程自动化:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct TestStruct
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] public char[] CharArray;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] public char[] CharArray2;
}
private void Button1_Click(object sender, RoutedEventArgs e)
{
TestStruct _TestStruct = new TestStruct();
IntPtr _IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(_TestStruct));
_TestStruct.CharArray = "abcd".ToCharArray();
_TestStruct.CharArray2 = "ab".ToCharArray();
_TestStruct = (TestStruct)FixArraySizes(_TestStruct); // Due to TestStruct being a struct, we must unbox the result.
Marshal.StructureToPtr(_TestStruct, _IntPtr, false);
// void TestFunction(IntPtr _Intptr);
Marshal.FreeHGlobal(_IntPtr);
}
private object FixArraySizes(object obj) {
var objType = obj.GetType();
var fieldInfos = objType.FindMembers(MemberTypes.Field, BindingFlags.Public | BindingFlags.Instance, (info, _) => ((FieldInfo)info).FieldType == typeof(char[]), null);
foreach (FieldInfo info in fieldInfos) {
var fieldValue = (char[])info.GetValue(obj);
var sizeOfArray = (int?)info.GetCustomAttributesData().FirstOrDefault(attr => attr.AttributeType == typeof(MarshalAsAttribute))?.NamedArguments.FirstOrDefault(arg => arg.MemberName == "SizeConst").TypedValue.Value;
if (sizeOfArray.HasValue)
{
fieldValue = FixArraySize(fieldValue, sizeOfArray.Value);
info.SetValue(obj, fieldValue);
}
}
return obj;
}
private char[] FixArraySize(char[] array, int expectedSize)
{
if (array.Length < expectedSize)
array = array.Concat(Enumerable.Repeat((char)0, expectedSize - array.Length)).ToArray();
return array;
}