我正在努力使用 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();
}
}
我收到此错误:
错误:您不能使用包含在不固定大小的缓冲区中 表达式。尝试使用固定语句。
由于我对 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,这将是从名称中编组字符的更好方法。
我还想表明,我已从结构声明中删除了固定和不安全的指令,因为这对于您尝试执行的操作来说不是必需的。
尝试
Encoding.ASCII.GetString(name, 1, name[0]);
以原始格式存储的字符串不是“空终止”(C 样式字符串)。
原始格式是 'char count then Count chars => 0x6 = 字符计数,A = 0 S = 1 H = 2 T = 3 O = 4 N = 5。
您尝试读取字符,直到遇到空字符。但没有空字符,它不是以空结尾的字符串。您必须为此设置自定义数据投射器或转换数据库。
我在这里找到了答案: 固定大小的缓冲区不能直接从“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)
。