【问题标题】:Converting Delphi variant record to C# struct将 Delphi 变体记录转换为 C# 结构
【发布时间】:2012-02-17 16:16:50
【问题描述】:

当我尝试从现有应用程序编写 C# 应用程序但在 Delphi 中开发时, 非常艰难,但掌握了一些方法,但现在我遇到了一个问题......

Delphi 代码包含以下代码:

type  
  TFruit = record
    name : string[20];
    case isRound : Boolean of // Choose how to map the next section
      True  :
        (diameter : Single);  // Maps to same storage as length
      False :
        (length   : Single;   // Maps to same storage as diameter
         width    : Single);
  end;

即一个变体记录(内部带有case 语句)并相应地构造记录及其大小。 另一方面,我正在尝试在 C# struct 中做同样的事情,但还没有成功,我希望有人能在这里帮助我。 所以只要让我知道是否有任何方法可以在 C# 中实现它。 提前谢谢....

【问题讨论】:

    标签: c# delphi


    【解决方案1】:

    您可以使用显式结构布局来复制此 Delphi 变体记录。但是,我不会打扰,因为您似乎不太可能真的希望分配给diameter 也分配给length,反之亦然。 Delphi 记录声明看起来可以追溯​​到 1990 年代中期的 Delphi 编码风格。现代 Delphi 代码很少会这样写。

    我会这样做:

    struct Fruit
    {
        string name;
        bool isRound;
        float diameter; // only valid when isRound is true
        float length;   // only valid when isRound is false
        float width;    // only valid when isRound is false
    }
    

    更优雅的选择是为每个结构字段提供属性的类。如果 3 个浮点数的属性 getter 和 setter 因isRound 的无效值而被访问,您将安排它们引发异常。

    【讨论】:

    • 如果他使用这个结构来调用非托管代码,那么这个逻辑就行不通了。
    • 不,但这对我来说似乎不太可能,问题并没有说明这一点。问题表明这是一个 Delphi -> C# 端口。
    【解决方案2】:

    也许这可以解决问题?

    这不是复制粘贴解决方案,请注意偏移量和数据大小可能需要根据 Delphi 结构的声明和/或对齐方式进行更改。

    [StructLayout(LayoutKind.Explicit)]
    unsafe struct Fruit
    {
        [FieldOffset(0)] public fixed char name[20];
        [FieldOffset(20)] public bool IsRound;
        [FieldOffset(21)] public float Diameter;
        [FieldOffset(21)] public float Length;
        [FieldOffset(25)] public float Width;
    }
    

    【讨论】:

    • 这有两个问题。 C#char 是两个字节,但 Delphi 短字符串是每个字符一个字节。而且你没有考虑对齐。该 Delphi 记录将被对齐,尽管编译器设置当然会影响这一点。
    • 这并不是一个复制粘贴的解决方案,而是纯粹的指示性。我会更新代码以反映,谢谢。
    • 未对齐的floats 很奇怪。与其说如果您需要它们在 Delphi 中完全一样的布局,它们应该正确对齐,而是对齐它们,并且仅当它们 在 Delphi 中对齐它们需要在 C# 中的布局相同,将其更改回来。
    • @hvd:是的——Delphi 记录没有被声明为打包,它有填充字节。直径为 24。
    【解决方案3】:

    这取决于你想做什么。

    如果您只是尝试制作相应的结构,请查看 David Heffernan 的答案。现在几乎没有理由将两个字段相互映射,除非它们真正代表同一事物。 (例如,单个项目或数组中的相同项目。)

    如果您实际上是在尝试共享文件,则需要按照 ananthonline 的答案进行查看,但是它的问题太大了,我无法将其放在评论中:

    不仅存在 Unicode 问题,而且 Delphi 短字符串在 C# 中没有相应的结构,因此不可能简单地在其上映射字段。

    那个字符串[20] 实际上包含 21 个字节,一个字节长度的代码,然后是 20 个字符的数据。您必须遵守长度代码,因为无法保证超出指定长度的内容 - 您可能会在那里找到垃圾。 (提示:如果要将记录写入磁盘,请务必在将新数据放入其中之前先对字段进行 zap。这使得在调试时检查磁盘上的文件变得更加容易。)

    因此你需要声明两个字段并编写代码在两端进行处理。

    既然你无论如何都必须这样做,我会更进一步,编写代码来处理其余部分,以便完全消除对不安全代码的需求。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-16
      • 2014-06-27
      • 1970-01-01
      • 1970-01-01
      • 2012-02-20
      • 1970-01-01
      相关资源
      最近更新 更多