简体   繁体   中英

Converting Delphi variant record to C# struct

As I am trying to code a C# application from an existing application but developed in Delphi, Very tough but managed some how till, but now I have come across a problem...

Delphi code contains following code:

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;

ie a variant record (with case statement inside) and accordingly record is constructed and its size too. On the other hand I am trying to do the same in C# struct, and haven't succeeded yet, I hope somemone can help me here. So just let me know if there's any way I can implement this in C#. Thanks in advance....

You could use an explicit struct layout to replicate this Delphi variant record. However, I would not bother since it seems pretty unlikely that you really want assignment to diameter to assign also to length , and vice versa. That Delphi record declaration looks like it dates from mid-1990s style of Delphi coding. Modern Delphi code would seldom be written that way.

I would just do it like this:

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
}

A more elegant option would be a class with properties for each struct field. And you would arrange that the property getters and setters for the 3 floats raised exceptions if they were accessed for an invalid value of isRound .

Perhaps this will do the trick?

This is NOT a copy-and-paste solution, note that the offsets and data sizes may need to be changed depending on how the Delphi structure is declared and/or aligned.

[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;
}

It depends on what you are trying to do.

If you're simply trying to make a corresponding structure then look at David Heffernan's answer. These days there is little justification for mapping two fields on top of each other unless they truly represent the same thing. (Say, individual items or the same items in an array.)

If you're actually trying to share files you need to look along the lines of ananthonline's answer but there's a problem with it that's big enough I couldn't put it in a comment:

Not only is there the Unicode issue but a Delphi shortstring has no corresponding structure in C# and thus it's impossible to simply map a field on top of it.

That string[20] actually comprises 21 bytes, a one-byte length code and then 20 characters worth of data. You have to honor the length code as there is no guarantee of what lies beyond the specified length--you're likely to find garbage there. (Hint: If the record is going to be written to disk always zap the field before putting new data in it. It makes it much easier to examine the file on disk when debugging.)

Thus you need to declare two fields and write code to process it on both ends.

Since you have to do that anyway I would go further and write code to handle the rest of it so as to eliminate the need for unsafe code at all.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM