在下面的代码中抛出异常。
'type could not be marshaled because the length of an embedded array instance does not match the declared length in the layout'
我知道这是因为字符串和字符数组的长度不匹配,所以我尝试用空白字符修复字符串的长度。
要添加空白字符,我应该知道运行时目标字符数组的长度,但我不能,因为字符数组成员还为空。
如何获取 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);
}
最佳答案
如果将 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;
}
关于c# - 如何在运行时知道属于结构体的 char 数组的长度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51568709/