Skip to content

hakakou/PrimaryConstructorConverter

Repository files navigation

Primary Constructor Converter

A .NET 9 console application that converts C# primary constructors (introduced in C# 12) to standard constructors.

Purpose

The primary purpose of this tool is to enable Doxygen documentation generation for C# projects that use primary constructors. Doxygen does not currently support C# 12 primary constructor syntax, which can cause documentation generation to fail or produce incomplete results. This tool acts as a filter to convert primary constructors to standard constructors that Doxygen can understand.

This tool does not modify your source code. It only modifies the input Doxygen receives to generate the documentation.

Usage with Doxygen

  1. Unzip to any folder on the computer (the example below uses c:\Tools\PrimaryConstructorConverter\)

  2. Update your Doxyfile as follows (modify the executable)

INPUT_FILTER           = 
FILTER_PATTERNS        = *.cs="c:\Tools\PrimaryConstructorConverter\PrimaryConstructorConverter.exe"
FILTER_SOURCE_FILES    = YES

Doxygen Configuration Notes

  • Replace the path with the actual path to the PrimaryConstructorConverter.exe on your system
  • On Linux/macOS, use: dotnet /path/to/PrimaryConstructorConverter.dll
  • The FILTER_SOURCE_FILES = YES setting is required for the filter to work
  • The original source files remain unchanged; only the documentation generation is affected

⚠️ Important Limitation: Line Number Changes

Doxygen filters must not add or remove lines from the source code, as this affects code anchors and cross-references in the generated documentation. However, this tool necessarily adds lines (fields, constructors) when converting primary constructors, which can cause the following issues:

  • Source code links in documentation may point to incorrect line numbers
  • Code anchors and cross-references may be misaligned
  • The "Go to source" feature in HTML documentation may jump to wrong locations

Workaround Options:

Option 1: Don't enable the source code browser (Recommended)

SOURCE_BROWSER = NO

This disables source code browsing but still generates full API documentation.

Option 2: Accept the line number offset Keep source browsing enabled and accept that line numbers in documentation won't match the actual source files. The documentation will still be functionally complete.

Option 3: Pre-convert your source files If you need accurate line numbers, convert your source files permanently using the command-line interface, commit the converted versions, and disable the filter:

# Convert a file
PrimaryConstructorConverter MyClass.cs > MyClass_converted.cs
# Then use normal Doxygen without filters

What It Does

This tool converts C# primary constructors to standard constructors for:

  • Classes: Converts primary constructor parameters to private readonly fields with a standard constructor
  • Structs: Converts primary constructor parameters to private readonly fields with a standard constructor
  • Records: Converts primary constructor parameters to public properties with init accessors and a standard constructor

Example Conversions

Class with Primary Constructor

Before:

public class Person(string firstName, string lastName, int age)
{
    public string GetFullName() => $"{firstName} {lastName}";
    public bool IsAdult() => age >= 18;
}

After:

public class Person
{
    private readonly string _firstName;
    private readonly string _lastName;
    private readonly int _age;
    
    public Person(string firstName, string lastName, int age)
    {
        _firstName = firstName;
        _lastName = lastName;
        _age = age;
    }
    
    public string GetFullName() => $"{_firstName} {_lastName}";
    public bool IsAdult() => _age >= 18;
}

Record with Primary Constructor

Before:

public record Product(string Name, decimal Price, int Stock);

After:

public record Product
{
    public string Name { get; init; }
    public decimal Price { get; init; }
    public int Stock { get; init; }
    
    public Product(string Name, decimal Price, int Stock)
    {
  Name = Name;
     Price = Price;
 Stock = Stock;
    }
}

Struct with Primary Constructor

Before:

public struct Point(int x, int y)
{
    public double GetDistance() => Math.Sqrt(x * x + y * y);
}

After:

public struct Point
{
    private readonly int _x;
    private readonly int _y;

    public Point(int x, int y)
    {
        _x = x;
        _y = y;
    }
    
    public double GetDistance() => Math.Sqrt(_x * _x + _y * _y);
}

Requirements

  • .NET 9.0 or later

Building from Source

dotnet build -c Release

License

MIT License. This project is free to use, modify, and distribute. See the LICENSE file for details.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages