Bridging Worlds

Introduction

Over the last few years, I've increasingly used C# and Delphi together, in some capacity, on the same project.

Typically, Delphi is the core application, with C# augmenting it. That could be via a Win32 host, an ASP.NET Core backend, or building tools that make large Delphi systems easier to understand and work with.

C# always seems to find its way into the picture.

The two technologies complement each other surprisingly well.

XQuery is a good example.


XQuery

In a previous role, I was onboarded to a large legacy Delphi estate of more than four million lines of code, backed by customer datasets stored across 850+ DBF files. Some of those files had 800+ columns. The underlying system used Sequiter CodeBase, a C++ engine over the FoxPro 2.6 format.

I needed answers to business questions: what had changed since a recent backup, how two customer configurations differed, where a specific value was being persisted, or which records across multiple companies matched some ad hoc criteria.

On one occasion, a support colleague and I couldn't determine where an external COM object was persisting an incoming value. With Delphi units running to 40,000 lines of deeply nested code, tracing it manually was like looking for a needle in a haystack.

Bespoke utilities to solve these problems typically took days or weeks to build. With the objective of reducing these tasks to minutes, I reached for C#.

I wrote a C# code generator that exported the low-level Delphi data structures into C#, generating entity and repository abstractions over an existing NuGet library named DbfDataReader.

Thanks to the Roslyn compiler services, it was simple to build a lightweight scripting IDE that brought the power of C# and LINQ to the legacy data, across one or many customer datasets.

Searching or filtering a table became trivial:

var scotia = Open("scotia");

// filter customers in the DevExpress Grid
Show(scotia.CUSTS);

No index selection. No space-padding search criteria. No special-case utility code.

One of the biggest advantages was the ability to query multiple customer datasets together:

var scotia = Open("scotia");
var metro  = Open("metro");

var details = scotia.CUSTS
    .Concat(metro.CUSTS)
    .Where(c => c.CURCODE == "GBP")
    .Select(c => new
    {
        Code = c.CODE,
        Name = c.NAME,
        Contact = c.CONTACT1,
        Phone = c.PHONE1
    });

Show(details);

We could poke a value into any of the hundreds of UI grids and controls and immediately discover which table and column it was stored in, pointing us directly to the underlying Delphi data structure.


Legacy Code Intelligence

A more recent Delphi role was another good example.

An ETL pipeline began with a Delphi console application extracting AST metadata from the source. A Python/local AI stage simplified the representation and generated descriptive comments for units, types and methods, before a C# importer combined the metadata with the corresponding source and method bodies and loaded everything into a normalized SQL Server database with full-text search.

I then built a C# analysis tool and hosted it directly inside Kitae, my Delphi developer workbench, using Win32 application hosting. The two applications communicated over TCP/IP.

The C# plugin enabled SQL queries and C#/LINQ scripts over the extracted code and metadata, generation of UML documentation, and VS Code interactivity.

The result was a development environment in which Delphi remained the primary workbench, while C# provided a powerful analytical layer over the two-million-line legacy codebase.

// fetch the twenty largest units
            
var results = Entities.Units
    .OrderByDescending(u => u.Loc)
    .Take(20)
    .Select(u => new Result
    {
        Name = u.Name,
        Loc = u.Loc
    })
    .ToList();

LoadGrid(results);

Abstract upward for understanding; trace downward for verification.

The purpose was to grasp the essential structure and behaviour of the system so I could trace that understanding back to the particulars of the implementation, as a precaution against an over-eager Claude.

CSharp Kitae

Conclusion

For desktop development, Delphi remains in a class of its own, while modern C#/.NET is a powerhouse for data processing. Used together, these two technologies complement each other extremely well, and bridging these worlds can yield incredible results.

My current R&D work continues to leverage this synergy, with ASP.NET Core supporting Delphi.

These days, it's rarely either Delphi or C# for me, but both.