Besides being collections of fields, records in Delphi and structures in C# can also have properties, methods, constructors, and operator overloads. While classes in Delphi and C# are always allocated on the heap, records, even those with methods and overloaded operators, are stored on the stack. Because records are allocated on the stack, your code is more efficient since stack allocation is faster than heap allocation. Since records in .NET aren't allocated on the managed heap, they are also not garbage collected, which again results in better overall performance.

Besides the allocation difference, there are several more differences between classes and records:

  • Classes support inheritance; records don't.

  • Classes support polymorphism; records don't.

  • Classes can have parameterless (default) constructors; records cannot. (In C#, records have an implicit parameterless constructor that is called to initialize record fields when you use the new operator. In Delphi, fields get initialized automatically, so there's no need to call the default constructor Create, and actually, you cannot call it.)

  • In Delphi for Win32 only records support operator overloading; classes don't. (In C# and Delphi for .NET, both classes and records support operator overloading.)

  • Records don't have destructors; classes do.

Listings 30-7 and 30-8 show how records with fields, properties, methods, and constructors work in Delphi (both flavors) and C#.

Listing 30-7: Records in Delphi for Win32 and Delphi for .NET

image from book
program Project1; {$APPTYPE CONSOLE} uses   SysUtils; type   TMyRecord = record   private     FX: Integer;     FY: Integer;     procedure SetX(Value: Integer);     procedure SetY(Value: Integer);   public     constructor Create(newX, newY: Integer);     procedure Display(const Prefix: string);     property X: Integer read FX write SetX;     property Y: Integer read FY write SetY;   end; constructor TMyRecord.Create(newX, newY: Integer); begin   // assign to properties to call SetX and SetY   // to take care of negative values   X := newX;   Y := newY; end; procedure TMyRecord.SetX(Value: Integer); begin   if Value >= 0 then     FX := Value   else     FX := 0; end; procedure TMyRecord.SetY(Value: Integer); begin   if Value >= 0 then     FY := Value   else     FY := 0; end; // Prefix is used only to get more meaningful output procedure TMyRecord.Display(const Prefix: string); begin   WriteLn(Prefix, 'X = ', Self.X);       // or just X   WriteLn(Prefix, 'Y = ', Self.Y);       // or just Y   WriteLn; end; var   a: TMyRecord;   b: TMyRecord;   c: TMyRecord; begin   { fields are initialized to 0, displays X = 0, Y = 0 }   a.Display('a.');   { using the custom constructor to initialize fields }   b := TMyRecord.Create(100, 200);   b.Display('b.');   { copies the entire record, not a reference (pointer) }   c := b;   c.X := 1;   c.Display('c.');           // c.X is 1   b.Display('b.');          // b.X remains 200   ReadLn; end.
image from book

Listing 30-8: Structures in C#

image from book
 using System; namespace Wordware.Records {    struct MyRecord    {       private int fx;       private int fy;       // x property       public int X       {         get {            return fx;         }         set {            fx = value >= 0 ? value : 0;         }       }       // y property       public int Y       {         get {            return fy;         }         set {            fy = value >= 0 ? value : 0;         }       }       /* custom constructor */       public MyRecord(int newX, int newY)       {         fx = newX;         fy = newY;       }       /* another constructor that accepts strings */       public MyRecord(string newX, string newY)       {         fx = System.Int32.Parse(newX);         fy = System.Int32.Parse(newY);       }       // there's no need for const when passing strings in .NET       public void Display(string prefix)       {         Console.WriteLine("{0}X = {1}", prefix, fx);         Console.WriteLine("{0}Y = {1}", prefix, fy);         Console.WriteLine();       }    }    class RecordUser    {        [STAThread]       static void Main(string[] args)       {         /* if you don't use the new operator, the fields are         unassigned, and Console.WriteLine doesn't compile */         // MyRecord a;         // Console.WriteLine(a.X);         /* initialized to default values */         MyRecord b = new MyRecord();         b.Display("b.");         /* call the custom (int, int) constructor */         MyRecord c = new MyRecord(1, 2);         c.Display("c.");         /* call the custom (string, string) constructor,            System.Int32.Parse understands spaces */         MyRecord d = new MyRecord(" 2   ", "10");         d.Display("d.");         /* struct assignment */         MyRecord e = new MyRecord(1000, 1001);         MyRecord f = e;           // only if "e" is completely initialized         f.Display("f.");         Console.ReadLine();       }    } }
image from book

Inside Delphi 2006
Inside Delphi 2006 (Wordware Delphi Developers Library)
ISBN: 1598220039
EAN: 2147483647
Year: 2004
Pages: 212
Authors: Ivan Hladni

Similar book on Amazon © 2008-2017.
If you may any questions please contact us: