{"id":24124679,"url":"https://github.com/devteam/immutype","last_synced_at":"2025-10-26T11:32:09.886Z","repository":{"id":37864716,"uuid":"429492504","full_name":"DevTeam/Immutype","owner":"DevTeam","description":"Immutability is easy!","archived":false,"fork":false,"pushed_at":"2025-02-11T14:32:16.000Z","size":137,"stargazers_count":46,"open_issues_count":0,"forks_count":3,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-22T18:07:21.036Z","etag":null,"topics":["csharp-sourcegenerator","dotnet","functional","functional-programming","immutability"],"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/DevTeam.png","metadata":{"files":{"readme":"README.md","changelog":null,"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-11-18T16:01:14.000Z","updated_at":"2025-03-15T00:46:13.000Z","dependencies_parsed_at":"2023-01-17T17:31:01.075Z","dependency_job_id":"8e666fe6-bc8c-497d-8a8f-a244bccb12e7","html_url":"https://github.com/DevTeam/Immutype","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DevTeam%2FImmutype","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DevTeam%2FImmutype/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DevTeam%2FImmutype/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DevTeam%2FImmutype/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DevTeam","download_url":"https://codeload.github.com/DevTeam/Immutype/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246230505,"owners_count":20744347,"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":["csharp-sourcegenerator","dotnet","functional","functional-programming","immutability"],"created_at":"2025-01-11T14:35:17.654Z","updated_at":"2025-10-26T11:32:04.846Z","avatar_url":"https://github.com/DevTeam.png","language":"C#","readme":"# Immutype\n\n[![NuGet](https://img.shields.io/nuget/v/Immutype)](https://www.nuget.org/packages/Immutype)\n[![License](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)\n[\u003cimg src=\"http://teamcity.jetbrains.com/app/rest/builds/buildType:(id:OpenSourceProjects_DevTeam_Immutype_BuildAndTestBuildType)/statusIcon\"/\u003e](http://teamcity.jetbrains.com/viewType.html?buildTypeId=OpenSourceProjects_DevTeam_Immutype_BuildAndTestBuildType\u0026guest=1)\n![GitHub Build](https://github.com/DevTeam/Immutype/actions/workflows/main.yml/badge.svg)\n\n_Immutype_ is [.NET code generator](https://docs.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/source-generators-overview) creating extension methods for records, structures, and classes marked by the attribute `````[Immutype.Target]````` to efficiently operate with instances of these types like with immutable ones.\n\nFor instance, for the type Foo for the constructor parameter *__values__* of type ```IEnumerable\u003cint\u003e``` following extension methods are generated:\n\n- ```Foo WithValues(this Foo it, params int[] values)``` - to replace values by the new ones using a method with variable number of arguments\n- ```Foo WithValues(this Foo it, IEnumerable\u003cint\u003e values)``` - to replace values by the new ones\n- ```Foo AddValues(this Foo it, params int[] values)``` - to add values using a method with variable number of arguments\n- ```Foo AddValues(this Foo it, IEnumerable\u003cint\u003e values)``` - to add values\n- ```Foo RemoveValues(this Foo it, params int[] values)``` - to remove values using a method with variable number of arguments\n- ```Foo RemoveValues(this Foo it, IEnumerable\u003cint\u003e values)``` - to remove values\n- ```Foo ClearValues(this Foo it)``` - to clear all values\n\nFor the type Foo for the constructor parameter *__value__* of other types, like ```int```, with default value ```99``` following extension methods are generated:\n\n- ```Foo WithValue(this Foo it, int value)``` - to replace a value by the new one\n- ```Foo WithDefaultValue(this Foo it)``` - to replace a value by the default value *__99__*\n\nThe extensions methods above are generating automatically for each ```public``` or ```internal``` type, like *__Foo__* marked by the attribute ```[Immutype.Target]``` in the static class named as *__FooExtensions__*. This generated class *__FooExtensions__* is static, has the same accessibility level and the same namespace like a target class *__Foo__*. Each generated static extension method has two attributes:\n- ```[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]``` - to improve performance\n- ```[Pure]``` - to indicate that this method is pure, that is, it does not make any visible state changes\n\n_Immutype_ supports nullable [reference](https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references) and [value](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/nullable-value-types) types and the following list of enumerable types:\n\n- Arrays\n- ```IEnumerable\u003cT\u003e```\n- ```List\u003cT\u003e```\n- ```IList\u003cT\u003e```\n- ```IReadOnlyCollection\u003cT\u003e```\n- ```IReadOnlyList\u003cT\u003e```\n- ```ICollection\u003cT\u003e```\n- ```HashSet\u003cT\u003e```\n- ```ISet\u003cT\u003e```\n- ```Queue\u003cT\u003e```\n- ```Stack\u003cT\u003e```\n- ```IReadOnlyCollection\u003cT\u003e```\n- ```IReadOnlyList\u003cT\u003e```\n- ```IReadOnlySet\u003cT\u003e```\n- ```ImmutableList\u003cT\u003e```\n- ```IImmutableList\u003cT\u003e```\n- ```ImmutableArray\u003cT\u003e```\n- ```ImmutableQueue\u003cT\u003e```\n- ```IImmutableQueue\u003cT\u003e```\n- ```ImmutableStack\u003cT\u003e```\n- ```IImmutableStack\u003cT\u003e```\n\n_Immutype_ supports [IIncrementalGenerator](https://docs.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.iincrementalgenerator) as well as [ISourceGenerator](https://docs.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.isourcegenerator) so it works quite effective.\n\n## NuGet package\n\n[![NuGet](https://img.shields.io/nuget/v/Immutype)](https://www.nuget.org/packages/Immutype)\n\n- Package Manager\n\n  ```\n  Install-Package Immutype\n  ```\n\n- .NET CLI\n\n  ```\n  dotnet add package Immutype\n  ```\n\n## Development environment requirements\n\n- [.NET SDK 5.0.102+](https://dotnet.microsoft.com/download/dotnet/5.0)\n- [C# v.6 or newer](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-version-history#c-version-40)\n\n## Supported frameworks\n\n- [.NET and .NET Core](https://docs.microsoft.com/en-us/dotnet/core/) 1.0+\n- [.NET Standard](https://docs.microsoft.com/en-us/dotnet/standard/net-standard) 1.0+\n- [.NET Framework](https://docs.microsoft.com/en-us/dotnet/framework/) 3.5+\n- [UWP/XBOX](https://docs.microsoft.com/en-us/windows/uwp/index)\n- [.NET IoT](https://dotnet.microsoft.com/apps/iot)\n- [Xamarin](https://dotnet.microsoft.com/apps/xamarin)\n- [.NET Multi-platform App UI (MAUI)](https://docs.microsoft.com/en-us/dotnet/maui/)\n\n\n## Usage Scenarios\n\n- Basics\n  - [Sample scenario](#sample-scenario)\n  - [Array](#array)\n  - [Applying defaults](#applying-defaults)\n  - [Clearing](#clearing)\n  - [Immutable collection](#immutable-collection)\n  - [Removing](#removing)\n  - [Generic types](#generic-types)\n  - [Nullable collection](#nullable-collection)\n  - [Set](#set)\n  - [Record with constructor](#record-with-constructor)\n  - [Explicit constructor choice](#explicit-constructor-choice)\n\n### Sample scenario\n\n\n\n``` CSharp\n[Immutype.Target]\ninternal record Person(\n    string Name,\n    bool HasPassport = true,\n    int Age = 0,\n    ImmutableArray\u003cPerson\u003e Friends = default);\n\npublic class SampleScenario\n{\n    public void Run()\n    {\n        var john = new Person(\"John\", false, 15)\n            .AddFriends(\n                new Person(\"David\").WithAge(16),\n                new Person(\"James\").WithAge(17)\n                    .WithFriends(new Person(\"Tyler\").WithAge(16)));\n            \n        john.Friends.Length.ShouldBe(2);\n\n        john = john.WithAge(16).WithDefaultHasPassport();\n        john.Age.ShouldBe(16);\n        john.HasPassport.ShouldBeTrue();\n\n        john = john.AddFriends(\n            new Person(\"Daniel\").WithAge(17),\n            new Person(\"Sophia\").WithAge(18));\n        \n        john.Friends.Length.ShouldBe(4);\n            \n        john = john.RemoveFriends(new Person(\"David\").WithAge(16));\n\n        john.Friends.Length.ShouldBe(3);\n    }\n}\n```\n\n\n\n### Array\n\n\n\n``` CSharp\n[Immutype.Target]\ninternal readonly record struct Person(string Name, int Age = 0, params Person[] Friends);\n\npublic class Array\n{ \n    public void Run()\n    {\n        var john = new Person(\"John\")\n            .WithAge(15)\n            .AddFriends(new Person(\"David\").WithAge(16))\n            .AddFriends(\n                new Person(\"James\"),\n                new Person(\"Daniel\").WithAge(17));\n        \n        john.Friends.Length.ShouldBe(3);\n    }\n}\n```\n\n\n\n### Applying defaults\n\n\n\n``` CSharp\n[Immutype.Target]\ninternal readonly record struct Person(string Name = \"John\", int Age = 17);\n\npublic class ApplyingDefaults\n{\n    public void Run()\n    {\n        var john = new Person(\"David\", 15)\n            .WithDefaultAge()\n            .WithDefaultName();\n        \n        john.Name.ShouldBe(\"John\");\n        john.Age.ShouldBe(17);\n    }\n}\n```\n\n\n\n### Clearing\n\n\n\n``` CSharp\n[Immutype.Target]\ninternal readonly record struct Person(\n    string Name,\n    int Age = 0,\n    params Person[] Friends);\n\npublic class Clearing\n{\n    public void Run()\n    {\n        var john = new Person(\"John\",15, new Person(\"David\").WithAge(16))\n            .AddFriends(new Person(\"James\"));\n\n        john = john.ClearFriends();\n        \n        john.Friends.Length.ShouldBe(0);\n    }\n}\n```\n\n\n\n### Immutable collection\n\n\n\n``` CSharp\n[Immutype.Target]\ninternal readonly struct Person\n{\n    public readonly string Name;\n    public readonly int Age;\n    public readonly IImmutableList\u003cPerson\u003e Friends;\n\n    public Person(\n        string name,\n        int age = 0,\n        IImmutableList\u003cPerson\u003e? friends = default)\n    {\n        Name = name;\n        Age = age;\n        Friends = friends ?? ImmutableList\u003cPerson\u003e.Empty;\n    }\n};\n\npublic class ImmutableCollection\n{\n    public void Run()\n    {\n        var john = new Person(\"John\",15)\n            .WithFriends(\n                new Person(\"David\").WithAge(16),\n                new Person(\"James\").WithAge(17))\n            .AddFriends(\n                new Person(\"David\").WithAge(22));\n        \n        john.Friends.Count.ShouldBe(3);\n    }\n}\n```\n\n\n\n### Removing\n\n\n\n``` CSharp\n[Immutype.Target]\ninternal readonly record struct Person(\n    string Name,\n    int Age = 0,\n    params Person[] Friends);\n\npublic class Removing\n{\n    public void Run()\n    {\n        var john = new Person(\"John\",15, new Person(\"David\").WithAge(16))\n            .AddFriends(new Person(\"James\"));\n\n        john = john.RemoveFriends(new Person(\"James\"));\n        \n        john.Friends.Length.ShouldBe(1);\n    }\n}\n```\n\n\n\n### Generic types\n\nIt is possible to use generic types including any generic constraints.\n\n``` CSharp\n[Immutype.Target]\ninternal record Person\u003cTAge\u003e(string Name, TAge Age = default, IEnumerable\u003cPerson\u003cTAge\u003e\u003e? Friends = default) \n    where TAge : struct;\n\npublic class GenericTypes\n{ \n    public void Run()\n    {\n        var john = new Person\u003cint\u003e(\"John\")\n            .WithAge(15)\n            .WithFriends(new Person\u003cint\u003e(\"David\").WithAge(16))\n            .AddFriends(\n                new Person\u003cint\u003e(\"James\"),\n                new Person\u003cint\u003e(\"Daniel\").WithAge(17));\n        \n        john.Friends?.Count().ShouldBe(3);\n    }\n}\n```\n\n\n\n### Nullable collection\n\n\n\n``` CSharp\n[Immutype.Target]\ninternal record Person(\n    string Name,\n    int? Age = default,\n    ICollection\u003cPerson\u003e? Friends = default);\n\npublic class NullableCollection\n{\n    public void Run()\n    {\n        var john = new Person(\"John\",15)\n            .AddFriends(\n                new Person(\"David\").WithAge(16),\n                new Person(\"James\").WithAge(17)\n                    .WithFriends(new Person(\"Tyler\").WithAge(16)));\n        \n        john.Friends?.Count.ShouldBe(2);\n    }\n}\n```\n\n\n\n### Set\n\n\n\n``` CSharp\n[Immutype.Target]\ninternal record Person(\n    string Name,\n    int Age = 0,\n    ISet\u003cPerson\u003e? Friends = default);\n\npublic class Set\n{\n    public void Run()\n    {\n        var john = new Person(\"John\",15)\n            .AddFriends(\n                new Person(\"David\").WithAge(16),\n                new Person(\"David\").WithAge(16),\n                new Person(\"James\").WithAge(17)\n                    .WithFriends(new Person(\"Tyler\").WithAge(16)));\n        \n        john.Friends?.Count.ShouldBe(2);\n    }\n}\n```\n\n\n\n### Record with constructor\n\n\n\n``` CSharp\n[Immutype.Target]\ninternal record Person\n{\n    public Person(\n        string name,\n        int? age = default,\n        ICollection\u003cPerson\u003e? friends = default)\n    {\n        Name = name;\n        Age = age;\n        Friends = friends;\n    }\n\n    public string Name { get; }\n\n    public int? Age { get; }\n\n    public ICollection\u003cPerson\u003e? Friends { get; }\n\n    public void Deconstruct(\n        out string name,\n        out int? age,\n        out ICollection\u003cPerson\u003e? friends)\n    {\n        name = Name;\n        age = Age;\n        friends = Friends;\n    }\n}\n\npublic class RecordWithConstructor\n{\n    public void Run()\n    {\n        var john = new Person(\"John\",15)\n            .WithFriends(\n                new Person(\"David\").WithAge(16),\n                new Person(\"James\").WithAge(17)\n                    .WithFriends(new Person(\"Tyler\").WithAge(16)));\n        \n        john.Friends?.Count.ShouldBe(2);\n    }\n}\n```\n\n\n\n### Explicit constructor choice\n\n\n\n``` CSharp\n[Immutype.Target]\ninternal readonly struct Person\n{\n    public readonly string Name;\n    public readonly int Age;\n    public readonly IImmutableList\u003cPerson\u003e Friends;\n\n    // You can explicitly select a constructor by marking it with the [Immutype.Target] attribute\n    [Immutype.Target]\n    public Person(\n        string name,\n        int age = 0,\n        IImmutableList\u003cPerson\u003e? friends = default)\n    {\n        Name = name;\n        Age = age;\n        Friends = friends ?? ImmutableList\u003cPerson\u003e.Empty;\n    }\n    \n    public Person(\n        string name,\n        int age,\n        IImmutableList\u003cPerson\u003e? friends,\n        int someArg = 99)\n    {\n        Name = name;\n        Age = age;\n        Friends = friends ?? ImmutableList\u003cPerson\u003e.Empty;\n    }\n};\n\npublic class ExplicitConstructorChoice\n{\n    public void Run()\n    {\n        var john = new Person(\"John\",15)\n            .WithFriends(\n                new Person(\"David\").WithAge(16),\n                new Person(\"James\").WithAge(17))\n            .AddFriends(\n                new Person(\"David\").WithAge(22));\n        \n        john.Friends.Count.ShouldBe(3);\n    }\n}\n```\n\n\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevteam%2Fimmutype","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevteam%2Fimmutype","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevteam%2Fimmutype/lists"}