c# - 如何在运行时知道属于结构体的 char 数组的长度

标签 c# arrays

在下面的代码中抛出异常。

'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/

相关文章:

c# - 真正的 MVVM 和第三方控件

具有不同输入的 c# .net 方法

c# - 查找所有程序集依赖项,Reflector 样式

c++ - 如何在 C++ 中追加字节数据?

javascript - 如何在 javascript 循环中为每个特定数据创建一个新数组?

arrays - F# 为什么在映射函数来对数组中的每个数组进行置乱时,数组不会以不同的方式进行置乱

c# - 用于将自定义字段添加到邮件表单或使用 C# 访问现有字段的 Outlook 插件

C# Web 服务从 WinForms 应用程序返回对象为 null

arrays - bash:如何更新隐式子 shell 中的关联数组?

javascript - Eloquent Javascript 练习 5.2。帮助整理思绪