C# 错误:无法使用不固定表达式中包含的固定大小缓冲区

问题描述 投票:0回答:4

我正在努力使用 C# 程序从数据库读取二进制记录。这些记录是用 Borland Delphi 创建的。这是一个例子:

//Delphi记录定义
  tBowler_Rec = 记录
  民众
    性别:t性别;
    Bowler_num:字节;
    名称:tString32;
    首字母缩写:字符串[3];
    ...
//对应的C#定义(非托管代码)
    [StructLayout(LayoutKind.Sequential, Pack=4)]
    公共不安全结构 tBowler_Rec
    {
        公共 tGender 性别;
        公共字节 Bowler_num;
        公共固定字节名称[32];
        公共固定字节首字母[3];
        ...

我实际上能够从 SQL Server 数据库中读取这个二进制结构,并在 Visual Studio 调试器中查看数据。耶!我可以毫无问题地访问“性别”和“bowler_num”等字段。耶!

问:如何将“name”转换为 C# 字符串?

示例名称是“ASHTON”。记忆中是这样的:

 x6阿什顿 x0 x0...

这是我尝试访问它的方法:


[StructLayout(LayoutKind.Sequential, Pack=4)]
public unsafe struct tBowler_Rec
{
    public tGender gender;
    public byte bowler_num;
    public fixed byte name[32];
    ...
    public string Name
    {
        get
        {
            StringBuilder sb = new StringBuilder();
            int ilen = name[0];
            for (int i = 1; i <= ilen; i++)
                sb.Append(name[i]);
            return sb.ToString();
        }
    }

我收到此错误:

错误:您不能使用包含在不固定大小的缓冲区中 表达式。尝试使用固定语句。

c# delphi interop
4个回答
2
投票

由于我对 Delphi 不太熟悉,所以我无法在

tString32
字段上给你直接答案。似乎是UnmanagedType.AnsiBStr

如果是这样的话,我会做这样的事情:

[StructLayout(LayoutKind.Sequential, Pack=4)]
public struct tBowler_Rec
{
    public tGender gender;
    public byte bowler_num;
    [MarshalAs(UnmanagedType.AnsiBStr)]
    public string name;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
    public char[] initials;

另请参阅我如何进行

initials
编组。如果 tString 不是 AnsiBStr,这将是从名称中编组字符的更好方法。

我还想表明,我已从结构声明中删除了固定和不安全的指令,因为这对于您尝试执行的操作来说不是必需的。


2
投票

尝试

Encoding.ASCII.GetString(name, 1, name[0]);

1
投票

以原始格式存储的字符串不是“空终止”(C 样式字符串)。

原始格式是 'char count then Count chars => 0x6 = 字符计数,A = 0 S = 1 H = 2 T = 3 O = 4 N = 5。

您尝试读取字符,直到遇到空字符。但没有空字符,它不是以空结尾的字符串。您必须为此设置自定义数据投射器或转换数据库。


0
投票

我在这里找到了答案: 固定大小的缓冲区不能直接从“this”对象使用

解决方案:

[StructLayout(LayoutKind.Sequential, Pack=4)]
public unsafe struct tBowler_Rec
{
    public tGender gender;
    public byte bowler_num;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst=32)]
    public byte[] name;
    ...
    public string Name
    {
        get
        {
            StringBuilder sb = new StringBuilder();
            int ilen = name[0];
            for (int i = 1; i <= ilen; i++)
                sb.Append(name[i]);
            return sb.ToString();
        }
    }

Vladimir 绝对是在正确的轨道上:根本问题是我需要将这个 Delphi 数组视为值类型,而不是 C#(引用类型)数组。解决方案是

MarshalAs(UnmanagedType.ByValArray)

© www.soinside.com 2019 - 2024. All rights reserved.