{"id":13629259,"url":"https://github.com/k94ll13nn3/AutoConstructor","last_synced_at":"2025-04-17T08:34:35.241Z","repository":{"id":39142062,"uuid":"343890132","full_name":"k94ll13nn3/AutoConstructor","owner":"k94ll13nn3","description":"C# source generator that generates a constructor from readonly fields/properties in a class or struct","archived":false,"fork":false,"pushed_at":"2025-03-01T09:23:31.000Z","size":525,"stargazers_count":56,"open_issues_count":0,"forks_count":4,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-04T05:40:32.898Z","etag":null,"topics":["constructor","csharp","csharp-sourcegenerator","dotnet","roslyn","source-generator"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/k94ll13nn3.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-03-02T19:33:36.000Z","updated_at":"2025-03-31T08:31:05.000Z","dependencies_parsed_at":"2023-10-16T02:52:59.949Z","dependency_job_id":"598a19af-60dc-49e0-a944-f35ac47f19d8","html_url":"https://github.com/k94ll13nn3/AutoConstructor","commit_stats":null,"previous_names":[],"tags_count":42,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k94ll13nn3%2FAutoConstructor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k94ll13nn3%2FAutoConstructor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k94ll13nn3%2FAutoConstructor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k94ll13nn3%2FAutoConstructor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/k94ll13nn3","download_url":"https://codeload.github.com/k94ll13nn3/AutoConstructor/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249326186,"owners_count":21251735,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["constructor","csharp","csharp-sourcegenerator","dotnet","roslyn","source-generator"],"created_at":"2024-08-01T22:01:05.963Z","updated_at":"2025-04-17T08:34:34.627Z","avatar_url":"https://github.com/k94ll13nn3.png","language":"C#","funding_links":[],"categories":["Content","Source Generators"],"sub_categories":["80. [AutoConstructor](https://ignatandrei.github.io/RSCG_Examples/v2/docs/AutoConstructor) , in the [Constructor](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#constructor) category","Other"],"readme":"# AutoConstructor\n\n[![NuGet](https://img.shields.io/nuget/vpre/AutoConstructor?logo=nuget\n)](https://www.nuget.org/packages/AutoConstructor/)\n[![GitHub release](https://img.shields.io/github/release/k94ll13nn3/AutoConstructor.svg?logo=github)](https://github.com/k94ll13nn3/AutoConstructor/releases/latest)\n[![GitHub license](https://img.shields.io/github/license/k94ll13nn3/AutoConstructor\n)](https://raw.githubusercontent.com/k94ll13nn3/AutoConstructor/main/LICENSE)\n![ci.yml](https://github.com/k94ll13nn3/AutoConstructor/workflows/.github/workflows/ci.yml/badge.svg)\n\nC# source generator that generates a constructor from readonly fields/properties in a class or struct.\n\n## Installation\n\n- Grab the latest package on [NuGet](https://www.nuget.org/packages/AutoConstructor/).\n\n## Requirements\n\n| Version | Visual Studio | .NET SDK |\n|---------|---------------|----------|\n| \u003c=1.3.0 | 16.10+        | 5.0.300+ |\n| \u003e=2.0.0 | 17.0+         | 6.0.100+ |\n| \u003e=5.0.0 | 17.6+         | 7.0.302+ |\n\n## Basic usage\n\nThe following code:\n\n```csharp\n[AutoConstructor]\npublic partial class MyClass\n{\n    private readonly MyDbContext _context;\n    private readonly IHttpClientFactory _clientFactory;\n    private readonly IService _service;\n\n    [AutoConstructorInject(\"options?.Value\", \"options\", typeof(IOptions\u003cApplicationOptions\u003e))]\n    private readonly ApplicationOptions _options;\n}\n```\n\nwill generate:\n\n```csharp\n//------------------------------------------------------------------------------\n// \u003cauto-generated\u003e\n//     This code was generated by the AutoConstructor source generator.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// \u003c/auto-generated\u003e\n//------------------------------------------------------------------------------\npartial class MyClass\n{\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"AutoConstructor\", \"5.0.0.0\")]\n    public MyClass(global::MyDbContext context, global::System.Net.Http.IHttpClientFactory clientFactory, global::IService service, global::Microsoft.Extensions.Options.IOptions\u003cglobal::ApplicationOptions\u003e options)\n    {\n        this._context = context;\n        this._clientFactory = clientFactory;\n        this._service = service;\n        this._options = options?.Value;\n    }\n}\n```\n\nA sample containing more cases is available at the end of this README.\n\n## How to use\n\nFor any class where the generator will be used:\n\n- Mark the class or struct as `partial`\n- Use `AutoConstructorAttribute` on the class or struct\n\nBy default, all `readonly` non-`static` fields without initialization will be used. They will be injected with the same name without any leading `_`.\n\nFields marked with `AutoConstructorIgnoreAttribute` will be ignored.\n\nUse `AutoConstructorInjectAttribute` to customize the behavior, usually when the injected parameter and the fields\ndo not have the same type. It takes three optional parameters:\n\n- `initializer`: a string that will be used to initialize the field (by example `myService.GetData()`), default to the `parameterName` if null or empty.\n- `parameterName`: the name of the parameter to used in the constructor  (by example `myService`), default to the field name trimmed if null or empty.\n- `injectedType`: the type of the parameter to used in the constructor  (by example `IMyService`), default to the field type if null.\n\nIf no parameters are provided, the behavior will be the same as without the attribute. Using the attribute on a field that would not be injected otherwise\nwon't make the field injectable.\n\nWhen using `AutoConstructorInjectAttribute`, the parameter name can be shared across multiple fields,\nand even use a parameter from another field not annotated with `AutoConstructorInjectAttribute`, but type must match.\n\n### Constructor accessibility\n\nConstructor accessibility can be changed using the optional parameter `accessibility` on `AutoConstructorAttribute` (like `[AutoConstructor(\"internal\")]`).\nThe default is `public` and it can be set to one of the following values:\n- `public`\n- `private`\n- `protected`\n- `internal`\n- `protected internal`\n- `private protected`\n\n### Initializer method\n\nIt is possible to add a method call at the end of the constructor. To do this, the attribute `AutoConstructorInitializer` can be added to\na parameterless method that returns void. This will generate a call to the method at the end.\n\n```csharp\n[AutoConstructor]\ninternal partial class Test\n{\n    private readonly int _t;\n\n    [AutoConstructorInitializer]\n    public void Initializer()\n    {\n    }\n}\n```\n\nwill generate\n\n```csharp\npublic Test(int t)\n{\n    this._t = t;\n\n    this.Initializer();\n}\n```\n\n### Configuring `base` call\n\nIt is possible to configure which base constructor is called when a type has a non-object base type and has its constructor generated. By default, a call to `base` is emitted only when the is only one constructor on the base type.\nThis behavior can be changed by adding a `[AutoConstructorDefaultBase]` on a constructor in the base type to indicate that it must be chosen as the base call.\n\nIf the base type is also generated, the `addDefaultBaseAttribute` parameter on `AutoConstructorAttribute` can be used to generate the attribute with the generated constructor.\n\n```csharp\ninternal class BaseClass\n{\n    private readonly int _t;\n\n    [AutoConstructorDefaultBase]\n    public BaseClass(int t1, int t3)\n    {\n        this._t = t1 + t3;\n    }\n\n    public BaseClass(int t)\n    {\n        this._t = t;\n    }\n\n    public BaseClass()\n    {\n    }\n}\n\n[AutoConstructor]\ninternal partial class Test : BaseClass\n{\n    private readonly int _t2;\n}\n```\n\nwill generate\n\n```csharp\npartial class Test\n{\n    public Test(int t2, int t1, int t3) : base(t1, t3)\n    {\n        this._t2 = t2;\n    }\n}\n```\n\n### Base constructor parameter matching\n\nWhen inheriting a class, a call to the base constructor will be generated. By default, any parameter with the same name and the same type in both the parent and the\nchild class will be matched together.\n\n```csharp\n// This (same name and type)\npublic class ParentClass\n{\n    private readonly int value;\n\n    public ParentClass(int value)\n    {\n        this.value = value;\n    }\n}\n\n[AutoConstructor]\npublic partial class Test : ParentClass\n{\n    private readonly int value;\n}\n\n// Generates\npartial class Test\n{\n    public Test(int service) : base(service)\n    {\n        this.service = service;\n    }\n}\n\n// This (same name but not same type)\npublic class ParentClass\n{\n    private readonly long value;\n\n    public ParentClass(long value)\n    {\n        this.value = value;\n    }\n}\n\n[AutoConstructor]\npublic partial class Test : ParentClass\n{\n    private readonly int value;\n}\n\n// Generates\npartial class Test\n{\n    public Test(int service, long b0__service) : base(b0__service)\n    {\n        this.service = service;\n    }\n}\n```\n\nIf wanted, the matching on the type can be disable by setting the parameter `matchBaseParameterOnName` on `AutoConstructorAttribute` as `true`.\n⚠️ This can lead to invalid code, since the type is no longer checked, anything can be used as a parameter with the same name. Use this only when necessary.\n\n```csharp\n// This (same name but not same type with matchBaseParameterOnName true)\npublic class ParentClass\n{\n    private readonly long value;\n\n    public ParentClass(long value)\n    {\n        this.value = value;\n    }\n}\n\n[AutoConstructor(matchBaseParameterOnName: true)]\npublic partial class Test : ParentClass\n{\n    private readonly int value;\n}\n\n// Generates\npartial class Test\n{\n    public Test(int service) : base(service)\n    {\n        this.service = service;\n    }\n}\n```\n\n### Properties injection\n\nGet-only properties (`public int Property { get; }`) are injected by the generator by default.\nNon get-only properties (`public int Property { get; set;}`) are injected only if marked with (`[field: AutoConstructorInject]`) attribute.\nThe behavior of the injection can be modified using auto-implemented property field-targeted attributes on its backing field. The following code show an injected get-only property with a custom injecter:\n\n```csharp\n[field: AutoConstructorInject(initializer: \"injected.ToString()\", injectedType: typeof(int), parameterName: \"injected\")]\npublic int Property { get; }\n```\n\n⚠️ The compiler support for auto-implemented property field-targeted attributes is not perfect, and Roslyn analyzers are not running on backings fields so some warnings may not be reported.\n\n## Configuration\n\n### Generating `ArgumentNullException`\n\nBy default, null checks with `ArgumentNullException` are not generated when needed.\n\nTo enable this behavior, set `AutoConstructor_GenerateArgumentNullExceptionChecks` to `true` in the project file:\n\n``` xml\n\u003cAutoConstructor_GenerateArgumentNullExceptionChecks\u003etrue\u003c/AutoConstructor_GenerateArgumentNullExceptionChecks\u003e\n```\n\n\u003cdetails\u003e\n  \u003csummary\u003e5.2.X and previous versions\u003c/summary\u003e\n  \n  To enable this behavior, set `AutoConstructor_DisableNullChecking` to `false` in the project file.\n\u003c/details\u003e\n\n### Generating `this()` calls\n\nBy default, if a non-generated parameterless constructor is available on the class (other than the implicit one), a call\nto `this()` is generated with the generated constructor.\nTo disable this behavior, set `AutoConstructor_GenerateThisCalls` to `false` in the project file:\n\n``` xml\n\u003cAutoConstructor_GenerateThisCalls\u003efalse\u003c/AutoConstructor_GenerateThisCalls\u003e\n```\n\nThis is also configurable at the attribute level with the `DisableThisCall` parameter on `AutoConstructorAttribute` (⚠ it is not possible force the generation at the attribute level if the generation is globally disabled).\n\n### Generating XML documentation comment\n\nBy default, no XML documentation comment will be generated for the constructor.\nTo enable this behavior, set `AutoConstructor_GenerateConstructorDocumentation` to `true` in the project file:\n\n``` xml\n\u003cAutoConstructor_GenerateConstructorDocumentation\u003etrue\u003c/AutoConstructor_GenerateConstructorDocumentation\u003e\n```\n\nThis will generate a default comment like this one, with each parameter reusing the corresponding field summary if available, and the parameter name otherwise:\n\n``` c#\n/// \u003csummary\u003e\n/// Initializes a new instance of the Test class.\n/// \u003c/summary\u003e\n/// \u003cparam name=\"\"t1\"\"\u003eSome field.\u003c/param\u003e\n/// \u003cparam name=\"\"t2\"\"\u003et2\u003c/param\u003e\n```\n\nBy using the `AutoConstructor_ConstructorDocumentationComment` property, you can configure the comment message:\n\n``` xml\n\u003cAutoConstructor_ConstructorDocumentationComment\u003eSome comment for the {0} class.\u003c/AutoConstructor_ConstructorDocumentationComment\u003e\n```\n\nThis will generate the following code:\n\n``` c#\n/// \u003csummary\u003e\n/// Some comment for the Test class.\n/// \u003c/summary\u003e\n/// \u003cparam name=\"\"t1\"\"\u003eSome field.\u003c/param\u003e\n/// \u003cparam name=\"\"t2\"\"\u003et2\u003c/param\u003e\n```\n\n### Generating a parameterless constructor\n\nIf needed, a parameterless constructor can also be generated alongside the generated constructor using the `addParameterless` option on `AutoConstructor`.\n\n``` csharp\n[AutoConstructor(addParameterless: true)]\npublic partial class Test\n{\n    public int Id { get; set; }\n    public string Name { get; set; }\n}\n```\n\nwill generate\n\n```csharp\npartial class Test\n{\n    #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor.\n    [global::System.ObsoleteAttribute(\"Not intended for direct usage.\", true)]\n    public Test()\n    {\n    }\n}\n```\n\nThis option can also be used without any fields or properties to inject, this will disable the warning that will normally be reported and generate a parameterless constructor.\n\n:warning: With inheritance, to be able to generate a parameterless constructor, the base type of the target type must have parameterless constructor itself.\n\nBy default, this constructor is marked as `[Obsolete]` with a default message. This is configurable with :\n\n``` xml\n\u003cAutoConstructor_MarkParameterlessConstructorAsObsolete\u003efalse\u003c/AutoConstructor_MarkParameterlessConstructorAsObsolete\u003e\n\u003cAutoConstructor_ParameterlessConstructorObsoleteMessage\u003eCustom obsolete message\u003c/AutoConstructor_ParameterlessConstructorObsoleteMessage\u003e\n```\n\n## Samples describing some cases\n\n### Sample for fields\n\nThe following code\n\n``` csharp\n[AutoConstructor]\npartial class Test\n{\n    private readonly string _name;\n\n    // Won't be injected\n    private readonly Uri _uri = new Uri(\"/non-modified\", UriKind.Relative);\n\n    // Won't be injected\n    [AutoConstructorIgnore]\n    private readonly DateTime _dateNotTaken;\n\n    // Won't be injected because not readonly. Attribute would be taken into account if this were a property, not a field.\n    [AutoConstructorInject]\n    private int  _stuff;\n\n    // Won't be injected\n    private int? _toto;\n\n    // Support for nullables\n    private readonly DateTime? _date;\n\n    // Support for generics\n    private readonly List\u003cDateTime\u003e _items;\n\n    // Inject with custom initializer\n    [AutoConstructorInject(\"guid.ToString()\", \"guid\", typeof(Guid))]\n    private readonly string _guidString;\n\n    // Use existing parameter defined with AutoConstructorInject\n    [AutoConstructorInject(\"guid.ToString().Length\", \"guid\", typeof(Guid))]\n    private readonly int _guidLength;\n\n    // Use existing parameter from a basic injection\n    [AutoConstructorInject(\"name.ToUpper()\", \"name\", typeof(string))]\n    private readonly string _nameShared;\n}\n```\n\nwill generate\n\n```csharp\n//------------------------------------------------------------------------------\n// \u003cauto-generated\u003e\n//     This code was generated by the AutoConstructor source generator.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// \u003c/auto-generated\u003e\n//------------------------------------------------------------------------------\npartial class Test\n{\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"AutoConstructor\", \"5.0.0.0\")]\n    public Test(string name, global::System.DateTime? date, global::System.Collections.Generic.List\u003cglobal::System.DateTime\u003e items, global::System.Guid guid)\n    {\n        this._name = name ?? throw new global::System.ArgumentNullException(nameof(name));\n        this._date = date;\n        this._items = items ?? throw new global::System.ArgumentNullException(nameof(items));\n        this._guidString = guid.ToString() ?? throw new global::System.ArgumentNullException(nameof(guid));\n        this._guidLength = guid.ToString().Length;\n        this._nameShared = name.ToUpper() ?? throw new global::System.ArgumentNullException(nameof(name));\n    }\n}\n```\n\n### Sample for get-only properties\n\nThe following code\n\n``` csharp\n[AutoConstructor]\npublic partial class Test\n{\n    [field: AutoConstructorInject]\n    public int Injected { get; }\n\n    public int AlsoInjectedEvenWhenMissingAttribute { get; }\n\n    /// \u003csummary\u003e\n    /// Some property.\n    /// \u003c/summary\u003e\n    [field: AutoConstructorInject]\n    public int InjectedWithDocumentation { get; }\n\n    [field: AutoConstructorInject]\n    public int InjectedBecauseExplicitInjection { get; set; }\n\n    [field: AutoConstructorInject]\n    public static int NotInjectedBecauseStatic { get; }\n\n    [field: AutoConstructorInject]\n    public int NotInjectedBecauseInitialized { get; } = 2;\n\n    [field: AutoConstructorIgnore]\n    public int NotInjectedBecauseHasIgnoreAttribute { get; }\n\n    [field: AutoConstructorInject(initializer: \"injected.ToString()\", injectedType: typeof(int), parameterName: \"injected\")]\n    public string InjectedWithoutCreatingAParam { get; }\n}\n```\n\nwill generate\n\n```csharp\n//------------------------------------------------------------------------------\n// \u003cauto-generated\u003e\n//     This code was generated by the AutoConstructor source generator.\n//\n//     Changes to this file may cause incorrect behavior and will be lost if\n//     the code is regenerated.\n// \u003c/auto-generated\u003e\n//------------------------------------------------------------------------------\npartial class Test\n{\n    /// \u003csummary\u003e\n    /// Initializes a new instance of the Test class.\n    /// \u003c/summary\u003e\n    /// \u003cparam name=\"injected\"\u003einjected\u003c/param\u003e\n    /// \u003cparam name=\"alsoInjectedEvenWhenMissingAttribute\"\u003ealsoInjectedEvenWhenMissingAttribute\u003c/param\u003e\n    /// \u003cparam name=\"injectedWithDocumentation\"\u003eSome property.\u003c/param\u003e\n    /// \u003cparam name=\"injectedBecauseExplicitInjection\"\u003einjectedBecauseExplicitInjection\u003c/param\u003e\n    [global::System.CodeDom.Compiler.GeneratedCodeAttribute(\"AutoConstructor\", \"5.0.0.0\")]\n    public Test(int injected, int alsoInjectedEvenWhenMissingAttribute, int injectedWithDocumentation, int injectedBecauseExplicitInjection)\n    {\n        this.Injected = injected;\n        this.AlsoInjectedEvenWhenMissingAttribute = alsoInjectedEvenWhenMissingAttribute;\n        this.InjectedWithDocumentation = injectedWithDocumentation;\n        this.InjectedBecauseExplicitInjection = injectedBecauseExplicitInjection;\n        this.InjectedWithoutCreatingAParam = injected.ToString() ?? throw new global::System.ArgumentNullException(nameof(injected));\n    }\n}\n```\n\n\n## Diagnostics\n\n### ACONS01\n\nThe `AutoConstructor` attribute is used on a class that is not partial.\n\n### ACONS02\n\nThe `AutoConstructor` attribute is used on a class without fields to inject (without specifying `addParameterless` as true).\n\n### ACONS03\n\nThe `AutoConstructorIgnore` attribute is used on a field that won't already be processed.\n\n### ACONS04\n\nThe `AutoConstructorInject` attribute is used on a field that won't already be processed.\n\n### ACONS05\n\nThe `AutoConstructorIgnore` or `AutoConstructorInject` are used on a class without the `AutoConstructor` attribute.\n\n### ACONS06\n\nA type specified in `AutoConstructorInject` attribute does not match the type of another parameter with the same name.\n\nIn the following sample, both fields will be injected with `guid` as parameter name, but one of type `string` and the other of type `Guid`,\npreventing the generator from running.\n\n``` csharp\npublic partial class Test\n{\n    [AutoConstructorInject(\"guid.ToString()\", \"guid\", typeof(Guid))]\n    private readonly string _guid2;\n    private readonly string _guid;\n}\n```\n\n### ACONS07\n\nThe accessibility defined in the `AutoConstructor` attribute is not an allowed value.\n\n### ACONS08\n\n`AutoConstructorInitializer` attribute used on multiple methods inside type.\n\n### ACONS09\n\n`AutoConstructorInitializer` attribute used on a method not returning void.\n\n### ACONS10\n\n`AutoConstructorInitializer` attribute used on a method with parameters.\n\n### ACONS11\n\n`AutoConstructorDefaultBase` attribute used on multiple constructors inside type.\n\n### ACONS12\n\nThe `addParameterless` option is used on a type whose base type does not have a parameterless constructor.\n\n### ACONS99\n\n`AutoConstructor_DisableNullChecking` is obsolete.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fk94ll13nn3%2FAutoConstructor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fk94ll13nn3%2FAutoConstructor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fk94ll13nn3%2FAutoConstructor/lists"}