DelphiCell

Top  Previous  Next

Pretranslated C# code > Pointers > DelphiCell

 

Overview

 

`DelphiCell<T>` represents an addressable variable containing a single value of type `T`.

 

It is used by Delphi2C# when translated Delphi code takes the address of a local variable or passes a local variable to an untyped `var` parameter.

 

In Delphi, the address of a local variable can be obtained with the `@` operator:

 

var

  Value: Integer;

  P: PInteger;

begin

  Value := 10;

  P := @Value;

  P^ := 20;

end;

 

After the pointer assignment, both `Value` and `P^` refer to the same storage location.

 

A normal C# local variable cannot be represented directly by the managed pointer runtime in this way. `DelphiCell<T>` therefore stores the value in a small shared storage object that can be accessed both as a value and through a pointer.

 

Declaration

 

 

public sealed class DelphiCell<T>

{

    public DelphiCell();

    public DelphiCell(T value);

 

    public T Value { get; set; }

 

    public Pointer<T> AsPointer();

    public UntypedPointer AsUntypedPointer();

}

 

Creating a cell

 

A cell can be created with the default value of `T`:

 

DelphiCell<int> value = new DelphiCell<int>();

 

It can also be initialized with a value:

 

DelphiCell<int> value = new DelphiCell<int>(10);

 

The contained value is accessed through the `Value` property:

 

value.Value = 20;

 

int currentValue = value.Value;

 

 

Creating a typed pointer

 

`AsPointer()` returns a `Pointer<T>` that refers to the value stored in the cell:

 

 

DelphiCell<int> value = new DelphiCell<int>(10);

Pointer<int> pointer = value.AsPointer();

 

pointer.Assign(20);

 

 

After the assignment, both expressions return `20`:

 

value.Value

pointer.Deref()

 

The pointer does not contain a separate copy of the value. The cell and the pointer share the same backing storage.

 

Creating an untyped pointer

 

`AsUntypedPointer()` returns an `UntypedPointer` that refers to the same storage location:

 

 

DelphiCell<int> value = new DelphiCell<int>(100);

UntypedPointer pointer = value.AsUntypedPointer();

 

pointer.As<int>().Assign(200);

 

After the assignment:

 

value.Value == 200

 

This is especially useful for translating untyped Delphi parameters.

 

For example, the Delphi declaration

 

procedure WriteValue(var AValue);

 

can be translated as:

 

public static void WriteValue(UntypedPointer aValue)

{

    Pointer<int> pointer = aValue.As<int>();

    pointer.Assign(31415);

}

 

 

The procedure can then be called with a cell:

 

 

DelphiCell<int> value = new DelphiCell<int>(0);

 

WriteValue(value.AsUntypedPointer());

 

 

After the call:

 

value.Value == 31415

 

Translation of local variables

 

A Delphi local variable whose address is never taken can normally remain a standard C# local variable.

 

Delphi:

 

var

  Value: Integer;

begin

  Value := 10;

end;

 

C#:

 

int value = 10;

 

If the Delphi code takes the address of the variable, Delphi2C# must use `DelphiCell<T>`.

 

Delphi:

 

var

  Value: Integer;

  P: PInteger;

begin

  Value := 10;

  P := @Value;

  P^ := 20;

end;

 

C#:

 

 

DelphiCell<int> value = new DelphiCell<int>(10);

Pointer<int> pointer = value.AsPointer();

 

pointer.Assign(20);

 

 

The original variable must then be accessed through its `Value` property:

 

 

bool result =

    value.Value == 20 &&

    pointer.Deref() == 20;

 

 

Why an array is used internally

 

`DelphiCell<T>` stores its value in an array containing exactly one element.

 

This provides a shared reference-based storage location that can be used by the pointer runtime. Multiple pointer views can refer to the same array element, and changes made through one view are visible through all other views.

 

Conceptually, the storage is equivalent to:

 

T[] storage = new T[1];

 

The `Value` property accesses `storage[0]`, while `AsPointer()` and `AsUntypedPointer()` create pointer views of the same element.

 

The array is an implementation detail and is not exposed publicly.

 

Difference from Pointer<T>(value)

 

Creating a pointer directly from a value creates a new storage location containing a copy:

 

int value = 10;

Pointer<int> pointer = new Pointer<int>(value);

 

pointer.Assign(20);

 

The original variable remains unchanged:

 

value == 10

 

Using `DelphiCell<T>` creates shared storage instead:

 

DelphiCell<int> value = new DelphiCell<int>(10);

Pointer<int> pointer = value.AsPointer();

 

pointer.Assign(20);

 

Now the cell contains the modified value:

 

value.Value == 20

 

For this reason, `DelphiCell<T>` must be used when translated code requires pointer writes to modify the original local variable.

 

Pointer copies

 

Pointers created from the same cell continue to refer to the same value:

 

DelphiCell<int> value = new DelphiCell<int>(10);

 

Pointer<int> pointer1 = value.AsPointer();

Pointer<int> pointer2 = pointer1;

 

pointer2.Assign(30);

 

All views now return the same value:

 

value.Value == 30

pointer1.Deref() == 30

pointer2.Deref() == 30

 

Lifetime

 

The backing storage remains available while the cell or one of its pointer views is referenced.

 

However, translated code should preserve the logical lifetime rules of the original Delphi local variable. A pointer to a local variable should not normally be stored and used after the translated method has finished.

 

Recommended generator mapping

 

 

@LocalVariable

    ->

DelphiCell<T> localVariable

Pointer<T> pointer = localVariable.AsPointer()

 

 

For an untyped `var` parameter:

 

 

UntypedProcedure(LocalVariable)

    ->

UntypedProcedure(localVariable.AsUntypedPointer())

 

 

Normal reads and writes of the translated variable must use the `Value` property:

 

 

LocalVariable := Value

    ->

localVariable.Value = value

 

Value := LocalVariable

    ->

value = localVariable.Value

 

 

Example

 

Delphi:

 

 

function TestLocalVariableAddress: Boolean;

var

  LocalValue: Integer;

  P: PInteger;

begin

  LocalValue := 111;

 

  P := @LocalValue;

  P^ := 222;

 

  Result :=

    (LocalValue = 222) and

    (P^ = 222);

end;

 

 

C#:

 

 

public static bool TestLocalVariableAddress()

{

    bool result = false;

 

    DelphiCell<int> localValue =

        new DelphiCell<int>(111);

 

    Pointer<int> pointer =

        localValue.AsPointer();

 

    pointer.Assign(222);

 

    result =

        localValue.Value == 222 &&

        pointer.Deref() == 222;

 

    return result;

}

 

 

Summary

 

`DelphiCell<T>` is used to represent a single addressable value in translated C# code.

 

It provides:

 

storage for one value of type `T`
normal access through the `Value` property
typed pointer access through `AsPointer()`
untyped pointer access through `AsUntypedPointer()`
shared storage between the value and all pointer views

 

The class is normally required only when Delphi code takes the address of a local variable or passes it through an untyped writable parameter.

 



This page belongs to the Delphi2C# Documentation

Delphi2C# home  Content