diff --git a/README.md b/README.md index 666dd3637..c6832f385 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -# RSCG - 268 Examples of Roslyn Source Code Generators / 16 created by Microsoft / +# RSCG - 269 Examples of Roslyn Source Code Generators / 16 created by Microsoft / -The RSCG_Examples repository is a comprehensive documentation system that automatically processes and showcases 268 Roslyn Source Code Generator (RSCG) examples. The system transforms individual RSCG projects into structured documentation with code examples and cross-referenced content with a searchable website and code example exports. +The RSCG_Examples repository is a comprehensive documentation system that automatically processes and showcases 269 Roslyn Source Code Generator (RSCG) examples. The system transforms individual RSCG projects into structured documentation with code examples and cross-referenced content with a searchable website and code example exports. This system serves as both a learning resource for .NET developers interested in source generators and an automated pipeline for maintaining up-to-date documentation about the RSCG ecosystem -## Latest Update : 2026-05-13 => 13 May 2026 +## Latest Update : 2026-05-14 => 14 May 2026 If you want to see examples with code, please click ***[List V2](https://ignatandrei.github.io/RSCG_Examples/v2/docs/List-of-RSCG)*** @@ -24,8 +24,30 @@ If you want to be notified each time I add a new RSCG example , please click htt ## Content -Those are the 268 Roslyn Source Code Generators that I have tested you can see and download source code example. +Those are the 269 Roslyn Source Code Generators that I have tested you can see and download source code example. ( including 16 from Microsoft ) +### 269. [LinkDotNet.Enumeration](https://ignatandrei.github.io/RSCG_Examples/v2/docs/LinkDotNet.Enumeration) , in the [Enum](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#enum) category + +Generated on : 2026-05-14 => 14 May 2026 + +
+ Expand + + + +Author: Steven Giesel + +Source code generated enumeration with completeness! + +Nuget: [https://www.nuget.org/packages/LinkDotNet.Enumeration/](https://www.nuget.org/packages/LinkDotNet.Enumeration/) + + +Link: [https://ignatandrei.github.io/RSCG_Examples/v2/docs/LinkDotNet.Enumeration](https://ignatandrei.github.io/RSCG_Examples/v2/docs/LinkDotNet.Enumeration) + +Source: [https://github.com/linkdotnet/Enumeration](https://github.com/linkdotnet/Enumeration) + +
+ ### 268. [GenerateDispose](https://ignatandrei.github.io/RSCG_Examples/v2/docs/GenerateDispose) , in the [Disposer](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#disposer) category Generated on : 2026-05-13 => 13 May 2026 diff --git a/later.md b/later.md index c08220127..97905fcae 100644 --- a/later.md +++ b/later.md @@ -1,6 +1,6 @@ # Just later -## Latest Update : 2026-05-13 => 13 May 2026 +## Latest Update : 2026-05-14 => 14 May 2026 diff --git a/v2/RSCGExamplesData/GeneratorDataRec.json b/v2/RSCGExamplesData/GeneratorDataRec.json index 311a91f4e..8e6f2e9ec 100644 --- a/v2/RSCGExamplesData/GeneratorDataRec.json +++ b/v2/RSCGExamplesData/GeneratorDataRec.json @@ -1624,5 +1624,11 @@ "Category": 18, "dtStart": "2026-05-13T00:00:00", "show": true + }, + { + "ID": "LinkDotNet.Enumeration", + "Category": 19, + "dtStart": "2026-05-14T00:00:00", + "show": true } ] \ No newline at end of file diff --git a/v2/book/examples/LinkDotNet.Enumeration.html b/v2/book/examples/LinkDotNet.Enumeration.html new file mode 100644 index 000000000..8aafe2698 --- /dev/null +++ b/v2/book/examples/LinkDotNet.Enumeration.html @@ -0,0 +1,64 @@ + +

RSCG nr 269 : LinkDotNet.Enumeration

+ +

Info

+Nuget : https://www.nuget.org/packages/LinkDotNet.Enumeration/ + +

You can find more details at : https://github.com/linkdotnet/Enumeration

+ +

Author :Steven Giesel

+ +

Source: https://github.com/linkdotnet/Enumeration

+ +

About

+ +Generating enumeration from classes in C# with matching + +

+ How to use +

+

+ Add reference to the LinkDotNet.Enumeration in the csproj +

+ + +

This was for me the starting code

+ +
+ I have coded the file Program.cs +
+ +
+ +
+ I have coded the file CarTypes.cs +
+ +
+

And here are the generated files

+ +
+ The file generated is CarTypes.g.cs +
+ + +
+ The file generated is EnumerationAttribute.g.cs +
+ + +

+ You can download the code and this page as pdf from + + https://ignatandrei.github.io/RSCG_Examples/v2/docs/LinkDotNet.Enumeration + +

+ + +

+ You can see the whole list at + + https://ignatandrei.github.io/RSCG_Examples/v2/docs/List-of-RSCG + +

+ diff --git a/v2/book/list.html b/v2/book/list.html index 31776b1e1..5c6342aa6 100644 --- a/v2/book/list.html +++ b/v2/book/list.html @@ -17,7 +17,7 @@

-This is the list of 268 RSCG with examples => +This is the list of 269 RSCG with examples =>

@@ -1098,6 +1098,10 @@

+ + + +
268 GenerateDispose
269LinkDotNet.Enumeration
diff --git a/v2/book/pandocHTML.yaml b/v2/book/pandocHTML.yaml index 43dbd53d3..fce328a0c 100644 --- a/v2/book/pandocHTML.yaml +++ b/v2/book/pandocHTML.yaml @@ -282,6 +282,7 @@ input-files: - examples/Aigamo.MatchGenerator.html - examples/Maestria.TypeProviders.html - examples/GenerateDispose.html +- examples/LinkDotNet.Enumeration.html # or you may use input-file: with a single value # defaults: diff --git a/v2/docFind.json b/v2/docFind.json index 801e7ba77..03b462871 100644 --- a/v2/docFind.json +++ b/v2/docFind.json @@ -1606,5 +1606,11 @@ "category": "Disposer", "href": "/RSCG_Examples/v2/docs/GenerateDispose/", "body": "A Rosyln-powered generator for the Dispose-pattern\u0027s boilerplate code." + }, + { + "title": "LinkDotNet.Enumeration", + "category": "Enum", + "href": "/RSCG_Examples/v2/docs/LinkDotNet.Enumeration/", + "body": "Source code generated enumeration with completeness!" } ] \ No newline at end of file diff --git a/v2/rscg_examples/GenerateDispose/description.json b/v2/rscg_examples/GenerateDispose/description.json index efbb168a3..2dbccef5b 100644 --- a/v2/rscg_examples/GenerateDispose/description.json +++ b/v2/rscg_examples/GenerateDispose/description.json @@ -9,7 +9,54 @@ "source":"https://github.com/ItaiTzur76/GenerateDispose" }, "data":{ - "goodFor":["Generating the Dispose method for a class that implements IDisposable."], + "goodFor":["GenerateDispose for boilerplate reduction for IDisposable pattern", +"### Purpose", +"A Roslyn source generator that replaces the 10+ lines of IDisposable boilerplate code with a single attribute.", +"It also automatically adapts the generated pattern when the class modifiers change (e.g. sealed to non-sealed).", +"", +"### How to Define", +"```csharp showLineNumbers", +"[GenerateDispose.SourceGenerators.GenerateDispose(nameof(Drop))]", +"partial class DALDB : IDisposable // : IDisposable is optional!", +"{", +" private ConnectionDB cn;", +" private ConnectionDB cn1;", +"", +" public DALDB()", +" {", +" cn = new ConnectionDB();", +" cn1 = new ConnectionDB();", +" }", +"", +" public void Drop() // Your custom disposal logic", +" {", +" cn.Dispose();", +" cn1.Dispose();", +" }", +"}", +"```", +"", +"- The class must be partial", +"- Pass nameof(YourDisposeMethod) to the attribute - the method must be callable with no arguments", +"", +"### What Gets Generated", +"- public void Dispose() (thread-safe, calls your method)", +"- A private int _isDisposed field for double-dispose protection", +"- Adapts to sealed vs non-sealed automatically (private vs protected virtual)", +"", +"### How to Use", +"```csharp showLineNumbers", +"using (var db = new DALDB())", +"{", +" // use db...", +"} // Dispose() called automatically", +"", +"```", +"### Key Benefits", +"- 10+ lines of boilerplate replaced by 1 attribute", +"- sealed changes auto-adapt the Dispose pattern", +"- No manual IDisposable wiring needed", +""], "csprojDemo":"IDisp.csproj", "csFiles":["Program.cs","DALDB.cs","ConnectionDB.cs"], "excludeDirectoryGenerated":[""], diff --git a/v2/rscg_examples/GenerateDispose/video.json b/v2/rscg_examples/GenerateDispose/video.json index 06510cbcc..ca1a3f5e0 100644 --- a/v2/rscg_examples/GenerateDispose/video.json +++ b/v2/rscg_examples/GenerateDispose/video.json @@ -8,7 +8,7 @@ {"typeStep":"browser","arg":"https://ignatandrei.github.io/RSCG_Examples/v2/docs/List-of-RSCG"}, {"typeStep":"text","arg": "My name is Andrei Ignat and I am deeply fond of Roslyn Source Code Generator. "}, -{"typeStep":"text","arg": "Today I will present GenerateDispose . Generating the Dispose method for a class that implements IDisposable. ."}, +{"typeStep":"text","arg": "Today I will present GenerateDispose . GenerateDispose for boilerplate reduction for IDisposable pattern### PurposeA Roslyn source generator that replaces the 10+ lines of IDisposable boilerplate code with a single attribute.It also automatically adapts the generated pattern when the class modifiers change (e.g. sealed to non-sealed).### How to Define```csharp showLineNumbers[GenerateDispose.SourceGenerators.GenerateDispose(nameof(Drop))]partial class DALDB : IDisposable // : IDisposable is optional!{ private ConnectionDB cn; private ConnectionDB cn1; public DALDB() { cn = new ConnectionDB(); cn1 = new ConnectionDB(); } public void Drop() // Your custom disposal logic { cn.Dispose(); cn1.Dispose(); }}```- The class must be partial- Pass nameof(YourDisposeMethod) to the attribute - the method must be callable with no arguments### What Gets Generated- public void Dispose() (thread-safe, calls your method)- A private int _isDisposed field for double-dispose protection- Adapts to sealed vs non-sealed automatically (private vs protected virtual)### How to Use```csharp showLineNumbersusing (var db = new DALDB()){ // use db...} // Dispose() called automatically```### Key Benefits- 10+ lines of boilerplate replaced by 1 attribute- sealed changes auto-adapt the Dispose pattern- No manual IDisposable wiring needed ."}, {"typeStep":"browser","arg":"https://www.nuget.org/packages/GenerateDispose/"}, {"typeStep":"text","arg": "The whole example is here"}, {"typeStep":"browser","arg":"https://ignatandrei.github.io/RSCG_Examples/v2/docs/GenerateDispose"}, diff --git a/v2/rscg_examples/LinkDotNet.Enumeration/description.json b/v2/rscg_examples/LinkDotNet.Enumeration/description.json new file mode 100644 index 000000000..d83a317db --- /dev/null +++ b/v2/rscg_examples/LinkDotNet.Enumeration/description.json @@ -0,0 +1,42 @@ +{ + "generator":{ + "name":"LinkDotNet.Enumeration", + "nuget":[ + "https://www.nuget.org/packages/LinkDotNet.Enumeration/" + ], + "link":"https://github.com/linkdotnet/Enumeration", + "author":"Steven Giesel", + "source":"https://github.com/linkdotnet/Enumeration" + }, + "data":{ + "goodFor":["Good for replacing enum + switch patterns with string-based enumerations with exhaustive pattern matching.", +"", +"### Purpose", +"A source code generator that creates string-based enumerations (similar to Java enums / DDD value objects) with exhaustive pattern matching, replacing enum + switch patterns.", +"", +"### How to Define", +"[Enumeration(Casing.Preserve, \"None\", \"Dacia\", \"Tesla\", \"BMW\", \"Mercedes\")]", +"public sealed partial record CarTypes;", +"", +"### How to Use", +"CarTypes.TryParse(\"BMW\", null, out var car);", +"car.Match(onBMW: () => \"this is bmw\", onDacia: () => \"this is dacia\", ...);", +"", +"### Key Features", +"- Exhaustive matching: Match() requires all values", +"- Create / TryCreate: throws vs returns bool", +"- IParsable: Minimal APIs & Model Binding", +"- Implicit string conversion", +"- CarTypes.All returns FrozenSet of CarTypes", +"- JSON: GenerateJsonConverter = true" +], + "csprojDemo":"EnumDemo.csproj", + "csFiles":["Program.cs","CarTypes.cs"], + "excludeDirectoryGenerated":[""], + "includeAdditionalFiles":[""] + }, + "links":{ + "blog":"", + "video":"" + } +} \ No newline at end of file diff --git a/v2/rscg_examples/LinkDotNet.Enumeration/nuget.txt b/v2/rscg_examples/LinkDotNet.Enumeration/nuget.txt new file mode 100644 index 000000000..a8e5e09b1 --- /dev/null +++ b/v2/rscg_examples/LinkDotNet.Enumeration/nuget.txt @@ -0,0 +1 @@ +Source code generated enumeration with completeness! \ No newline at end of file diff --git a/v2/rscg_examples/LinkDotNet.Enumeration/readme.txt b/v2/rscg_examples/LinkDotNet.Enumeration/readme.txt new file mode 100644 index 000000000..c4bd87e89 --- /dev/null +++ b/v2/rscg_examples/LinkDotNet.Enumeration/readme.txt @@ -0,0 +1,142 @@ +# Enumeration + +[![.NET](https://github.com/linkdotnet/Enumeration/actions/workflows/dotnet.yml/badge.svg)](https://github.com/linkdotnet/Enumeration/actions/workflows/dotnet.yml) +[![Nuget](https://img.shields.io/nuget/dt/LinkDotNet.Enumeration)](https://www.nuget.org/packages/LinkDotNet.Enumeration/) +[![GitHub tag](https://img.shields.io/github/v/tag/linkdotnet/Enumeration?include_prereleases&logo=github&style=flat-square)](https://github.com/linkdotnet/Enumeration/releases) + +Source code generated string Enumeration with completeness! + +## What is in the box? + +This source code generator let's you easily create string based enumerations with a lot of features. + +```csharp +[Enumeration("Red", "Green", "Blue")] +public sealed partial record Color; +``` + +That's all you need to do to create a string based enumeration. You can either use it like this: + +```csharp +var color = Color.Red; + +// Create it by a string key: +var color = Color.Create("Red"); +``` + +## Exhaustiveness + +The great benefit of the library is that you have support for exhaustiveness: + + +```csharp + +var color = Color.Create("Red"); + +color.Match( + red => Console.WriteLine("It's red!"), + green => Console.WriteLine("It's green!"), + blue => Console.WriteLine("It's blue!") +); +``` + +Or return a value: + +```csharp +var color = Color.Create("Red"); + +var colorCode = color.Match( + red => "#FF0000", + green => "#00FF00", + blue => "#0000FF" +); +``` + +## More features! + +### Controlling field names + +The `Enumeration` attribute accepts an optional first argument of type `Casing` to control how the static member names are derived from the string values. By default, the library uses `PascalCase` to convert string values into member names. If you want to preserve the original casing of the string values, you can set the `Casing` to `Preserve`. + +```csharp +[Enumeration(Casing.Preserve, "red", "green", "blue")] +public sealed partial class Color; +``` + +Generates: + +```csharp +public sealed partial class Color +{ + public static readonly Color red = new("red"); + public static readonly Color green = new("green"); + public static readonly Color blue = new("blue"); + // ... +``` + +The default is `PascalCase` to feel "natural" to C# developers. + +### Creating from a string key + +Two methods are exposed `Create` and `TryCreate` to create an instance of the enumeration from a string key. The `Create` method will throw an `ArgumentException` if the key is not valid, while the `TryCreate` method will return a boolean indicating whether the creation was successful and output the created value through an out parameter. + +```csharp +var color = Color.Create("Red"); // Throws if "Red" is not a valid key + +if (Color.TryCreate("Red", out var color)) +{ + // Use color +} +else +{ + // Handle invalid key +} +``` + +### Parsing (IParsable) + +The generated types implement `IParsable` and `ISpanParsable`, making them compatible with modern .NET features like Minimal APIs and Model Binding. + +```csharp +if (Color.TryParse("Red", null, out var color)) +{ + // Use color +} +``` + +### Implicit/Explicit Conversions + +Instances of the generated enumeration can be implicitly converted to strings (returns the `Key` property), and strings can be explicitly converted back to the enumeration type (calls `Create`). + +```csharp +string colorKey = Color.Red; // Implicit conversion +var color = (Color)"Green"; // Explicit conversion +``` + +### Equality and Comparison + +Records implement value-based equality by default. For classes, `IEquatable` is automatically implemented, comparing the `Key` property. + +```csharp +var isRed = Color.Red == "Red"; // String comparison +var areEqual = Color.Red.Equals(Color.Create("Red")); // Value equality +``` + +### Getting all values + +Calling `All` will return a collection of all possible values. This is implemented using a `FrozenSet` to ensure immutability and thread-safety. + +## `JsonConverter` Generation + +The library allows via the `GenerateJsonConverter` property on the `Enumeration` attribute to generate a `JsonConverter` for the enumeration type. This converter will handle serialization and deserialization of the enumeration values as their string keys. + +```csharp +[Enumeration("Red", "Green", "Blue", GenerateJsonConverter = true)] +public sealed partial record Color; +``` + +This will generate a `JsonConverter` that can be used with `System.Text.Json` to serialize and deserialize `Color` instances as their string keys. The generated converter is called `{TypeName}JsonConverter`. + +### Limitations + +* Your code should run at least `net8.0` or later, as the library uses things like `FrozenSet`. diff --git a/v2/rscg_examples/LinkDotNet.Enumeration/src/.tours/LinkDotNet.Enumeration.tour b/v2/rscg_examples/LinkDotNet.Enumeration/src/.tours/LinkDotNet.Enumeration.tour new file mode 100644 index 000000000..3c71f8147 --- /dev/null +++ b/v2/rscg_examples/LinkDotNet.Enumeration/src/.tours/LinkDotNet.Enumeration.tour @@ -0,0 +1,42 @@ + +{ + "$schema": "https://aka.ms/codetour-schema", + "title": "LinkDotNet.Enumeration", + "steps": + [ + { + "file": "EnumDemo/EnumDemo.csproj", + "description": "First, we add Nuget [LinkDotNet.Enumeration](https://www.nuget.org/packages/LinkDotNet.Enumeration/) in csproj ", + "pattern": "LinkDotNet.Enumeration" + } + + ,{ + "file": "EnumDemo/CarTypes.cs", + "description": "File CarTypes.cs ", + "pattern": "this is the code" + } + + ,{ + "file": "EnumDemo/Program.cs", + "description": "File Program.cs \r\n>> dotnet run --project EnumDemo/EnumDemo.csproj ", + "pattern": "this is the code" + } + + + ,{ + "file": "EnumDemo/obj/GX/LinkDotNet.Enumeration/LinkDotNet.Enumeration.EnumerationGenerator/EnumerationAttribute.g.cs", + "description": "Generated File 2 from 2 : EnumerationAttribute.g.cs ", + "line": 1 + } + + ,{ + "file": "EnumDemo/obj/GX/LinkDotNet.Enumeration/LinkDotNet.Enumeration.EnumerationGenerator/CarTypes.g.cs", + "description": "Generated File 1 from 2 : CarTypes.g.cs ", + "line": 1 + } + + ], + + "ref": "main" + +} \ No newline at end of file diff --git a/v2/rscg_examples/LinkDotNet.Enumeration/src/EnumDemo.sln b/v2/rscg_examples/LinkDotNet.Enumeration/src/EnumDemo.sln new file mode 100644 index 000000000..ace1b5ec0 --- /dev/null +++ b/v2/rscg_examples/LinkDotNet.Enumeration/src/EnumDemo.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.36401.2 d17.14 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnumDemo", "EnumDemo\EnumDemo.csproj", "{9D8848B1-F882-46F9-8036-C1C47BA503F0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9D8848B1-F882-46F9-8036-C1C47BA503F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9D8848B1-F882-46F9-8036-C1C47BA503F0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9D8848B1-F882-46F9-8036-C1C47BA503F0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9D8848B1-F882-46F9-8036-C1C47BA503F0}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {420BBB7E-4EC0-4A41-98F7-E573A6501983} + EndGlobalSection +EndGlobal diff --git a/v2/rscg_examples/LinkDotNet.Enumeration/src/EnumDemo/CarTypes.cs b/v2/rscg_examples/LinkDotNet.Enumeration/src/EnumDemo/CarTypes.cs new file mode 100644 index 000000000..12065a5ac --- /dev/null +++ b/v2/rscg_examples/LinkDotNet.Enumeration/src/EnumDemo/CarTypes.cs @@ -0,0 +1,5 @@ +using LinkDotNet.Enumeration; +namespace EnumDemo; + +[Enumeration(Casing.Preserve,"None", "Dacia", "Tesla", "BMW", "Mercedes")] +public sealed partial record CarTypes; diff --git a/v2/rscg_examples/LinkDotNet.Enumeration/src/EnumDemo/EnumDemo.csproj b/v2/rscg_examples/LinkDotNet.Enumeration/src/EnumDemo/EnumDemo.csproj new file mode 100644 index 000000000..bc7486c66 --- /dev/null +++ b/v2/rscg_examples/LinkDotNet.Enumeration/src/EnumDemo/EnumDemo.csproj @@ -0,0 +1,22 @@ + + + + Exe + net10.0 + enable + enable + + + + true + $(BaseIntermediateOutputPath)\GX + + + + + + + + + + diff --git a/v2/rscg_examples/LinkDotNet.Enumeration/src/EnumDemo/Program.cs b/v2/rscg_examples/LinkDotNet.Enumeration/src/EnumDemo/Program.cs new file mode 100644 index 000000000..db3b964ac --- /dev/null +++ b/v2/rscg_examples/LinkDotNet.Enumeration/src/EnumDemo/Program.cs @@ -0,0 +1,20 @@ +// See https://aka.ms/new-console-template for more information +using EnumDemo; +using System.Reflection; + +Console.WriteLine("Hello, World!"); +if(!CarTypes.TryParse("BMW", null,out var car)) +{ + Console.WriteLine("Invalid car type"); + return; +} + +var message = car.Match( + onBMW: () => "this is bmw", + onDacia: () => "this is dacia", + onMercedes: () => "this is mercedes", + onNone: () => "this is none", + onTesla: () => "this is tesla" + ); + +Console.WriteLine(message); diff --git a/v2/rscg_examples/LinkDotNet.Enumeration/video.json b/v2/rscg_examples/LinkDotNet.Enumeration/video.json new file mode 100644 index 000000000..597157159 --- /dev/null +++ b/v2/rscg_examples/LinkDotNet.Enumeration/video.json @@ -0,0 +1,39 @@ +{ + "scriptName": "LinkDotNet.Enumeration", + "steps": +[ + {"typeStep":"exec","arg":"clipchamp.exe launch"}, + {"typeStep":"text","arg": "Welcome to Roslyn Examples"}, + {"typeStep":"text","arg":"If you want to see more examples , see List Of RSCG"}, + {"typeStep":"browser","arg":"https://ignatandrei.github.io/RSCG_Examples/v2/docs/List-of-RSCG"}, + {"typeStep":"text","arg": "My name is Andrei Ignat and I am deeply fond of Roslyn Source Code Generator. "}, + +{"typeStep":"text","arg": "Today I will present LinkDotNet.Enumeration . Good for replacing enum + switch patterns with string-based enumerations with exhaustive pattern matching.### PurposeA source code generator that creates string-based enumerations (similar to Java enums / DDD value objects) with exhaustive pattern matching, replacing enum + switch patterns.### How to Define[Enumeration(Casing.Preserve, "None", "Dacia", "Tesla", "BMW", "Mercedes")]public sealed partial record CarTypes;### How to UseCarTypes.TryParse("BMW", null, out var car);car.Match(onBMW: () => "this is bmw", onDacia: () => "this is dacia", ...);### Key Features- Exhaustive matching: Match() requires all values- Create / TryCreate: throws vs returns bool- IParsable: Minimal APIs & Model Binding- Implicit string conversion- CarTypes.All returns FrozenSet of CarTypes- JSON: GenerateJsonConverter = true ."}, +{"typeStep":"browser","arg":"https://www.nuget.org/packages/LinkDotNet.Enumeration/"}, +{"typeStep":"text","arg": "The whole example is here"}, +{"typeStep":"browser","arg":"https://ignatandrei.github.io/RSCG_Examples/v2/docs/LinkDotNet.Enumeration"}, +{"typeStep":"text","arg": "You can download the code from here"}, +{"typeStep":"browser","arg":"https://ignatandrei.github.io/RSCG_Examples/v2/docs/LinkDotNet.Enumeration#download-example-net--c-"}, +{"typeStep":"text","arg":"Here is the code downloaded "}, +{"typeStep":"exec","arg":"explorer.exe /select,D:\\gth\\RSCG_Examples\\v2\\rscg_examples\\LinkDotNet.Enumeration\\src\\EnumDemo.sln"}, +{"typeStep":"text","arg": "So , let's start the project with Visual Studio Code "}, +{"typeStep":"stepvscode","arg": "-n D:\\gth\\RSCG_Examples\\v2\\rscg_examples\\LinkDotNet.Enumeration\\src"}, + +{"typeStep":"text","arg": "To use it ,you will put the Nuget LinkDotNet.Enumeration into the csproj "}, + +{"typeStep":"stepvscode","arg": "-r -g D:\\gth\\RSCG_Examples\\v2\\rscg_examples\\LinkDotNet.Enumeration\\src\\EnumDemo\\EnumDemo.csproj"}, + +{"typeStep":"text","arg": "And now I will show you an example of using LinkDotNet.Enumeration"}, + +{"typeStep":"hide","arg": "now execute the tour in VSCode"}, +{"typeStep":"tour", "arg": "src/.tours/"}, +{"typeStep":"text","arg":" And I will execute the project"}, +{"typeStep":"showproj", "arg":"EnumDemo.csproj"}, +{"typeStep":"text","arg":" This concludes the project"}, +{"typeStep":"waitseconds","arg":"30"}, +{"typeStep":"text","arg": "Remember, you can download the code from here"}, +{"typeStep":"browser","arg":"https://ignatandrei.github.io/RSCG_Examples/v2/docs/LinkDotNet.Enumeration#download-example-net--c-", +SpeakTest=" "}, +{"typeStep":"waitseconds","arg":"30"}, +] +} diff --git a/v2/rscg_examples_site/docs/Authors/Steven_Giesel.md b/v2/rscg_examples_site/docs/Authors/Steven_Giesel.md index 02c1707ad..344449349 100644 --- a/v2/rscg_examples_site/docs/Authors/Steven_Giesel.md +++ b/v2/rscg_examples_site/docs/Authors/Steven_Giesel.md @@ -1,7 +1,9 @@ # Author : Steven Giesel -Number RSCG: 1 +Number RSCG: 2 1 [BuildInfo](/docs/BuildInfo) [![Nuget](https://img.shields.io/nuget/dt/BuildInfo?label=BuildInfo)](https://www.nuget.org/packages/BuildInfo/) ![GitHub Repo stars](https://img.shields.io/github/stars/linkdotnet/BuildInformation?style=social) 2024-01-20 + 2 [LinkDotNet.Enumeration](/docs/LinkDotNet.Enumeration) [![Nuget](https://img.shields.io/nuget/dt/LinkDotNet.Enumeration?label=LinkDotNet.Enumeration)](https://www.nuget.org/packages/LinkDotNet.Enumeration/) ![GitHub Repo stars](https://img.shields.io/github/stars/linkdotnet/Enumeration?style=social) 2026-05-14 + diff --git a/v2/rscg_examples_site/docs/Categories/Enum.md b/v2/rscg_examples_site/docs/Categories/Enum.md index 01d77f115..64c9feed6 100644 --- a/v2/rscg_examples_site/docs/Categories/Enum.md +++ b/v2/rscg_examples_site/docs/Categories/Enum.md @@ -1,6 +1,6 @@

Enum

-Number RSCG: 14 +Number RSCG: 15 1 [Aigamo.MatchGenerator](/docs/Aigamo.MatchGenerator) [![Nuget](https://img.shields.io/nuget/dt/Aigamo.MatchGenerator?label=Aigamo.MatchGenerator)](https://www.nuget.org/packages/Aigamo.MatchGenerator/) ![GitHub Repo stars](https://img.shields.io/github/stars/ycanardeau/MatchGenerator?style=social) 2026-04-08 @@ -20,13 +20,15 @@ Number RSCG: 14 9 [jos.enumeration](/docs/jos.enumeration) [![Nuget](https://img.shields.io/nuget/dt/jos.enumeration?label=jos.enumeration)](https://www.nuget.org/packages/jos.enumeration/) ![GitHub Repo stars](https://img.shields.io/github/stars/joseftw/jos.enumeration?style=social) 2025-07-20 - 10 [NetEscapades.EnumGenerators](/docs/NetEscapades.EnumGenerators) [![Nuget](https://img.shields.io/nuget/dt/NetEscapades.EnumGenerators?label=NetEscapades.EnumGenerators)](https://www.nuget.org/packages/NetEscapades.EnumGenerators/) ![GitHub Repo stars](https://img.shields.io/github/stars/andrewlock/NetEscapades.EnumGenerators?style=social) 2023-04-16 + 10 [LinkDotNet.Enumeration](/docs/LinkDotNet.Enumeration) [![Nuget](https://img.shields.io/nuget/dt/LinkDotNet.Enumeration?label=LinkDotNet.Enumeration)](https://www.nuget.org/packages/LinkDotNet.Enumeration/) ![GitHub Repo stars](https://img.shields.io/github/stars/linkdotnet/Enumeration?style=social) 2026-05-14 - 11 [PMart.Enumeration](/docs/PMart.Enumeration) [![Nuget](https://img.shields.io/nuget/dt/PMart.Enumeration.Generator?label=PMart.Enumeration.Generator)](https://www.nuget.org/packages/PMart.Enumeration.Generator/)[![Nuget](https://img.shields.io/nuget/dt/PMart.Enumeration?label=PMart.Enumeration)](https://www.nuget.org/packages/PMart.Enumeration/) ![GitHub Repo stars](https://img.shields.io/github/stars/p-martinho/Enumeration?style=social) 2025-03-25 + 11 [NetEscapades.EnumGenerators](/docs/NetEscapades.EnumGenerators) [![Nuget](https://img.shields.io/nuget/dt/NetEscapades.EnumGenerators?label=NetEscapades.EnumGenerators)](https://www.nuget.org/packages/NetEscapades.EnumGenerators/) ![GitHub Repo stars](https://img.shields.io/github/stars/andrewlock/NetEscapades.EnumGenerators?style=social) 2023-04-16 - 12 [RapidEnum](/docs/RapidEnum) [![Nuget](https://img.shields.io/nuget/dt/RapidEnum?label=RapidEnum)](https://www.nuget.org/packages/RapidEnum/) ![GitHub Repo stars](https://img.shields.io/github/stars/hanachiru/RapidEnum?style=social) 2025-10-04 + 12 [PMart.Enumeration](/docs/PMart.Enumeration) [![Nuget](https://img.shields.io/nuget/dt/PMart.Enumeration.Generator?label=PMart.Enumeration.Generator)](https://www.nuget.org/packages/PMart.Enumeration.Generator/)[![Nuget](https://img.shields.io/nuget/dt/PMart.Enumeration?label=PMart.Enumeration)](https://www.nuget.org/packages/PMart.Enumeration/) ![GitHub Repo stars](https://img.shields.io/github/stars/p-martinho/Enumeration?style=social) 2025-03-25 - 13 [requiredenum](/docs/requiredenum) [![Nuget](https://img.shields.io/nuget/dt/requiredenum?label=requiredenum)](https://www.nuget.org/packages/requiredenum/) ![GitHub Repo stars](https://img.shields.io/github/stars/emptycoder/RequiredEnum?style=social) 2025-08-14 + 13 [RapidEnum](/docs/RapidEnum) [![Nuget](https://img.shields.io/nuget/dt/RapidEnum?label=RapidEnum)](https://www.nuget.org/packages/RapidEnum/) ![GitHub Repo stars](https://img.shields.io/github/stars/hanachiru/RapidEnum?style=social) 2025-10-04 - 14 [TaggedEnum](/docs/TaggedEnum) [![Nuget](https://img.shields.io/nuget/dt/TaggedEnum?label=TaggedEnum)](https://www.nuget.org/packages/TaggedEnum/) ![GitHub Repo stars](https://img.shields.io/github/stars/al0rid4l/SixTatami?style=social) 2026-04-05 + 14 [requiredenum](/docs/requiredenum) [![Nuget](https://img.shields.io/nuget/dt/requiredenum?label=requiredenum)](https://www.nuget.org/packages/requiredenum/) ![GitHub Repo stars](https://img.shields.io/github/stars/emptycoder/RequiredEnum?style=social) 2025-08-14 + + 15 [TaggedEnum](/docs/TaggedEnum) [![Nuget](https://img.shields.io/nuget/dt/TaggedEnum?label=TaggedEnum)](https://www.nuget.org/packages/TaggedEnum/) ![GitHub Repo stars](https://img.shields.io/github/stars/al0rid4l/SixTatami?style=social) 2026-04-05 \ No newline at end of file diff --git a/v2/rscg_examples_site/docs/Categories/_PrimitiveEnum.mdx b/v2/rscg_examples_site/docs/Categories/_PrimitiveEnum.mdx index 6a65a15e1..a712a7d88 100644 --- a/v2/rscg_examples_site/docs/Categories/_PrimitiveEnum.mdx +++ b/v2/rscg_examples_site/docs/Categories/_PrimitiveEnum.mdx @@ -18,15 +18,17 @@ 9 [jos.enumeration](/docs/jos.enumeration) [![Nuget](https://img.shields.io/nuget/dt/jos.enumeration?label=jos.enumeration)](https://www.nuget.org/packages/jos.enumeration/) ![GitHub Repo stars](https://img.shields.io/github/stars/joseftw/jos.enumeration?style=social) 2025-07-20 - 10 [NetEscapades.EnumGenerators](/docs/NetEscapades.EnumGenerators) [![Nuget](https://img.shields.io/nuget/dt/NetEscapades.EnumGenerators?label=NetEscapades.EnumGenerators)](https://www.nuget.org/packages/NetEscapades.EnumGenerators/) ![GitHub Repo stars](https://img.shields.io/github/stars/andrewlock/NetEscapades.EnumGenerators?style=social) 2023-04-16 + 10 [LinkDotNet.Enumeration](/docs/LinkDotNet.Enumeration) [![Nuget](https://img.shields.io/nuget/dt/LinkDotNet.Enumeration?label=LinkDotNet.Enumeration)](https://www.nuget.org/packages/LinkDotNet.Enumeration/) ![GitHub Repo stars](https://img.shields.io/github/stars/linkdotnet/Enumeration?style=social) 2026-05-14 - 11 [PMart.Enumeration](/docs/PMart.Enumeration) [![Nuget](https://img.shields.io/nuget/dt/PMart.Enumeration.Generator?label=PMart.Enumeration.Generator)](https://www.nuget.org/packages/PMart.Enumeration.Generator/)[![Nuget](https://img.shields.io/nuget/dt/PMart.Enumeration?label=PMart.Enumeration)](https://www.nuget.org/packages/PMart.Enumeration/) ![GitHub Repo stars](https://img.shields.io/github/stars/p-martinho/Enumeration?style=social) 2025-03-25 + 11 [NetEscapades.EnumGenerators](/docs/NetEscapades.EnumGenerators) [![Nuget](https://img.shields.io/nuget/dt/NetEscapades.EnumGenerators?label=NetEscapades.EnumGenerators)](https://www.nuget.org/packages/NetEscapades.EnumGenerators/) ![GitHub Repo stars](https://img.shields.io/github/stars/andrewlock/NetEscapades.EnumGenerators?style=social) 2023-04-16 - 12 [RapidEnum](/docs/RapidEnum) [![Nuget](https://img.shields.io/nuget/dt/RapidEnum?label=RapidEnum)](https://www.nuget.org/packages/RapidEnum/) ![GitHub Repo stars](https://img.shields.io/github/stars/hanachiru/RapidEnum?style=social) 2025-10-04 + 12 [PMart.Enumeration](/docs/PMart.Enumeration) [![Nuget](https://img.shields.io/nuget/dt/PMart.Enumeration.Generator?label=PMart.Enumeration.Generator)](https://www.nuget.org/packages/PMart.Enumeration.Generator/)[![Nuget](https://img.shields.io/nuget/dt/PMart.Enumeration?label=PMart.Enumeration)](https://www.nuget.org/packages/PMart.Enumeration/) ![GitHub Repo stars](https://img.shields.io/github/stars/p-martinho/Enumeration?style=social) 2025-03-25 - 13 [requiredenum](/docs/requiredenum) [![Nuget](https://img.shields.io/nuget/dt/requiredenum?label=requiredenum)](https://www.nuget.org/packages/requiredenum/) ![GitHub Repo stars](https://img.shields.io/github/stars/emptycoder/RequiredEnum?style=social) 2025-08-14 + 13 [RapidEnum](/docs/RapidEnum) [![Nuget](https://img.shields.io/nuget/dt/RapidEnum?label=RapidEnum)](https://www.nuget.org/packages/RapidEnum/) ![GitHub Repo stars](https://img.shields.io/github/stars/hanachiru/RapidEnum?style=social) 2025-10-04 - 14 [TaggedEnum](/docs/TaggedEnum) [![Nuget](https://img.shields.io/nuget/dt/TaggedEnum?label=TaggedEnum)](https://www.nuget.org/packages/TaggedEnum/) ![GitHub Repo stars](https://img.shields.io/github/stars/al0rid4l/SixTatami?style=social) 2026-04-05 + 14 [requiredenum](/docs/requiredenum) [![Nuget](https://img.shields.io/nuget/dt/requiredenum?label=requiredenum)](https://www.nuget.org/packages/requiredenum/) ![GitHub Repo stars](https://img.shields.io/github/stars/emptycoder/RequiredEnum?style=social) 2025-08-14 + + 15 [TaggedEnum](/docs/TaggedEnum) [![Nuget](https://img.shields.io/nuget/dt/TaggedEnum?label=TaggedEnum)](https://www.nuget.org/packages/TaggedEnum/) ![GitHub Repo stars](https://img.shields.io/github/stars/al0rid4l/SixTatami?style=social) 2026-04-05 ### See category diff --git a/v2/rscg_examples_site/docs/RSCG-Examples/GenerateDispose.md b/v2/rscg_examples_site/docs/RSCG-Examples/GenerateDispose.md index c8ace5a38..907a556dc 100644 --- a/v2/rscg_examples_site/docs/RSCG-Examples/GenerateDispose.md +++ b/v2/rscg_examples_site/docs/RSCG-Examples/GenerateDispose.md @@ -1,7 +1,7 @@ --- sidebar_position: 2680 title: 268 - GenerateDispose -description: Generating the Dispose method for a class that implements IDisposable. +description: GenerateDispose for boilerplate reduction for IDisposable pattern slug: /GenerateDispose --- import Tabs from '@theme/Tabs'; @@ -163,7 +163,148 @@ Happy coding! ### About :::note -Generating the Dispose method for a class that implements IDisposable. +GenerateDispose for boilerplate reduction for IDisposable pattern + + +### Purpose + + +A Roslyn source generator that replaces the 10+ lines of IDisposable boilerplate code with a single attribute. + + +It also automatically adapts the generated pattern when the class modifiers change (e.g. sealed to non-sealed). + + + + + +### How to Define + + +```csharp showLineNumbers + + +[GenerateDispose.SourceGenerators.GenerateDispose(nameof(Drop))] + + +partial class DALDB : IDisposable // : IDisposable is optional! + + +{ + + + private ConnectionDB cn; + + + private ConnectionDB cn1; + + + + + + public DALDB() + + + { + + + cn = new ConnectionDB(); + + + cn1 = new ConnectionDB(); + + + } + + + + + + public void Drop() // Your custom disposal logic + + + { + + + cn.Dispose(); + + + cn1.Dispose(); + + + } + + +} + + +``` + + + + + +- The class must be partial + + +- Pass nameof(YourDisposeMethod) to the attribute - the method must be callable with no arguments + + + + + +### What Gets Generated + + +- public void Dispose() (thread-safe, calls your method) + + +- A private int _isDisposed field for double-dispose protection + + +- Adapts to sealed vs non-sealed automatically (private vs protected virtual) + + + + + +### How to Use + + +```csharp showLineNumbers + + +using (var db = new DALDB()) + + +{ + + + // use db... + + +} // Dispose() called automatically + + + + + +``` + + +### Key Benefits + + +- 10+ lines of boilerplate replaced by 1 attribute + + +- sealed changes auto-adapt the Dispose pattern + + +- No manual IDisposable wiring needed + + + ::: diff --git a/v2/rscg_examples_site/docs/RSCG-Examples/LinkDotNet.Enumeration.md b/v2/rscg_examples_site/docs/RSCG-Examples/LinkDotNet.Enumeration.md new file mode 100644 index 000000000..56d6d6d75 --- /dev/null +++ b/v2/rscg_examples_site/docs/RSCG-Examples/LinkDotNet.Enumeration.md @@ -0,0 +1,693 @@ +--- +sidebar_position: 2690 +title: 269 - LinkDotNet.Enumeration +description: Good for replacing enum + switch patterns with string-based enumerations with exhaustive pattern matching. +slug: /LinkDotNet.Enumeration +--- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import TOCInline from '@theme/TOCInline'; +import SameCategory from '../Categories/_PrimitiveEnum.mdx'; + +# LinkDotNet.Enumeration by Steven Giesel + + + + +## NuGet / site data +[![Nuget](https://img.shields.io/nuget/dt/LinkDotNet.Enumeration?label=LinkDotNet.Enumeration)](https://www.nuget.org/packages/LinkDotNet.Enumeration/) +[![GitHub last commit](https://img.shields.io/github/last-commit/linkdotnet/Enumeration?label=updated)](https://github.com/linkdotnet/Enumeration) +![GitHub Repo stars](https://img.shields.io/github/stars/linkdotnet/Enumeration?style=social) + +## Details + +### Info +:::info + +Name: **LinkDotNet.Enumeration** + +Source code generated enumeration with completeness! + +Author: Steven Giesel + +NuGet: +*https://www.nuget.org/packages/LinkDotNet.Enumeration/* + + +You can find more details at https://github.com/linkdotnet/Enumeration + +Source: https://github.com/linkdotnet/Enumeration + +::: + +### Author +:::note +Steven Giesel +![Alt text](https://github.com/linkdotnet.png) +::: + +## Original Readme +:::note + +### Enumeration + +[![.NET](https://github.com/linkdotnet/Enumeration/actions/workflows/dotnet.yml/badge.svg)](https://github.com/linkdotnet/Enumeration/actions/workflows/dotnet.yml) +[![Nuget](https://img.shields.io/nuget/dt/LinkDotNet.Enumeration)](https://www.nuget.org/packages/LinkDotNet.Enumeration/) +[![GitHub tag](https://img.shields.io/github/v/tag/linkdotnet/Enumeration?include_prereleases&logo=github&style=flat-square)](https://github.com/linkdotnet/Enumeration/releases) + +Source code generated string Enumeration with completeness! + +###### What is in the box? + +This source code generator let's you easily create string based enumerations with a lot of features. + +```csharp +[Enumeration("Red", "Green", "Blue")] +public sealed partial record Color; +``` + +That's all you need to do to create a string based enumeration. You can either use it like this: + +```csharp +var color = Color.Red; + +// Create it by a string key: +var color = Color.Create("Red"); +``` + +###### Exhaustiveness + +The great benefit of the library is that you have support for exhaustiveness: + + +```csharp + +var color = Color.Create("Red"); + +color.Match( + red => Console.WriteLine("It's red!"), + green => Console.WriteLine("It's green!"), + blue => Console.WriteLine("It's blue!") +); +``` + +Or return a value: + +```csharp +var color = Color.Create("Red"); + +var colorCode = color.Match( + red => "#FF0000", + green => "#00FF00", + blue => "#0000FF" +); +``` + +###### More features! + +######### Controlling field names + +The `Enumeration` attribute accepts an optional first argument of type `Casing` to control how the static member names are derived from the string values. By default, the library uses `PascalCase` to convert string values into member names. If you want to preserve the original casing of the string values, you can set the `Casing` to `Preserve`. + +```csharp +[Enumeration(Casing.Preserve, "red", "green", "blue")] +public sealed partial class Color; +``` + +Generates: + +```csharp +public sealed partial class Color +{ + public static readonly Color red = new("red"); + public static readonly Color green = new("green"); + public static readonly Color blue = new("blue"); + // ... +``` + +The default is `PascalCase` to feel "natural" to C# developers. + +######### Creating from a string key + +Two methods are exposed `Create` and `TryCreate` to create an instance of the enumeration from a string key. The `Create` method will throw an `ArgumentException` if the key is not valid, while the `TryCreate` method will return a boolean indicating whether the creation was successful and output the created value through an out parameter. + +```csharp +var color = Color.Create("Red"); // Throws if "Red" is not a valid key + +if (Color.TryCreate("Red", out var color)) +{ + // Use color +} +else +{ + // Handle invalid key +} +``` + +######### Parsing (IParsable) + +The generated types implement `IParsable` and `ISpanParsable`, making them compatible with modern .NET features like Minimal APIs and Model Binding. + +```csharp +if (Color.TryParse("Red", null, out var color)) +{ + // Use color +} +``` + +######### Implicit/Explicit Conversions + +Instances of the generated enumeration can be implicitly converted to strings (returns the `Key` property), and strings can be explicitly converted back to the enumeration type (calls `Create`). + +```csharp +string colorKey = Color.Red; // Implicit conversion +var color = (Color)"Green"; // Explicit conversion +``` + +######### Equality and Comparison + +Records implement value-based equality by default. For classes, `IEquatable` is automatically implemented, comparing the `Key` property. + +```csharp +var isRed = Color.Red == "Red"; // String comparison +var areEqual = Color.Red.Equals(Color.Create("Red")); // Value equality +``` + +######### Getting all values + +Calling `All` will return a collection of all possible values. This is implemented using a `FrozenSet` to ensure immutability and thread-safety. + +###### `JsonConverter` Generation + +The library allows via the `GenerateJsonConverter` property on the `Enumeration` attribute to generate a `JsonConverter` for the enumeration type. This converter will handle serialization and deserialization of the enumeration values as their string keys. + +```csharp +[Enumeration("Red", "Green", "Blue", GenerateJsonConverter = true)] +public sealed partial record Color; +``` + +This will generate a `JsonConverter` that can be used with `System.Text.Json` to serialize and deserialize `Color` instances as their string keys. The generated converter is called `\{TypeName}\}JsonConverter`. + +######### Limitations + +* Your code should run at least `net8.0` or later, as the library uses things like `FrozenSet`. + + +::: + +### About +:::note + +Good for replacing enum + switch patterns with string-based enumerations with exhaustive pattern matching. + + + + + +### Purpose + + +A source code generator that creates string-based enumerations (similar to Java enums / DDD value objects) with exhaustive pattern matching, replacing enum + switch patterns. + + + + + +### How to Define + + +[Enumeration(Casing.Preserve, "None", "Dacia", "Tesla", "BMW", "Mercedes")] + + +public sealed partial record CarTypes; + + + + + +### How to Use + + +CarTypes.TryParse("BMW", null, out var car); + + +car.Match(onBMW: () => "this is bmw", onDacia: () => "this is dacia", ...); + + + + + +### Key Features + + +- Exhaustive matching: Match() requires all values + + +- Create / TryCreate: throws vs returns bool + + +- IParsable: Minimal APIs & Model Binding + + +- Implicit string conversion + + +- CarTypes.All returns FrozenSet of CarTypes + + +- JSON: GenerateJsonConverter = true + + +::: + +## How to use + +### Example (source csproj, source files) + + + + + +This is the CSharp Project that references **LinkDotNet.Enumeration** +```xml showLineNumbers {16} + + + + Exe + net10.0 + enable + enable + + + + true + $(BaseIntermediateOutputPath)\GX + + + + + + + + + + + +``` + + + + + + This is the use of **LinkDotNet.Enumeration** in *Program.cs* + +```csharp showLineNumbers +// See https://aka.ms/new-console-template for more information +using EnumDemo; +using System.Reflection; + +Console.WriteLine("Hello, World!"); +if(!CarTypes.TryParse("BMW", null,out var car)) +{ + Console.WriteLine("Invalid car type"); + return; +} + +var message = car.Match( + onBMW: () => "this is bmw", + onDacia: () => "this is dacia", + onMercedes: () => "this is mercedes", + onNone: () => "this is none", + onTesla: () => "this is tesla" + ); + +Console.WriteLine(message); + +``` + + + + + This is the use of **LinkDotNet.Enumeration** in *CarTypes.cs* + +```csharp showLineNumbers +using LinkDotNet.Enumeration; +namespace EnumDemo; + +[Enumeration(Casing.Preserve,"None", "Dacia", "Tesla", "BMW", "Mercedes")] +public sealed partial record CarTypes; + +``` + + + + +### Generated Files + +Those are taken from $(BaseIntermediateOutputPath)\GX + + + + +```csharp showLineNumbers +// +#nullable enable + +using System; +using System.Collections.Frozen; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +namespace EnumDemo; + +[DebuggerDisplay("{Key}")] +public sealed partial record CarTypes : IParsable, ISpanParsable, ISpanFormattable +{ + /// Gets the string key that identifies this enumeration value. + public string Key \{ get; init; \} = default!; + + private CarTypes(string key) + { + ArgumentException.ThrowIfNullOrWhiteSpace(key); + Key = key; + } + + /// Gets the instance for None. + public static readonly CarTypes None = new("None"); + /// Gets the instance for Dacia. + public static readonly CarTypes Dacia = new("Dacia"); + /// Gets the instance for Tesla. + public static readonly CarTypes Tesla = new("Tesla"); + /// Gets the instance for BMW. + public static readonly CarTypes BMW = new("BMW"); + /// Gets the instance for Mercedes. + public static readonly CarTypes Mercedes = new("Mercedes"); + + /// Gets a frozen set of all valid instances. Ordering is not guaranteed. + public static FrozenSet All \{ get; \} = + new CarTypes[] \{ None, Dacia, Tesla, BMW, Mercedes }.ToFrozenSet(); + + /// Creates the instance matching . + /// The key to look up. Must not be null, empty, or whitespace. + /// The matching instance. + /// Thrown when is null, empty, or whitespace. + /// Thrown when does not match any known value. + public static CarTypes Create(string key) + { + ArgumentException.ThrowIfNullOrWhiteSpace(key); + return key switch + { + "None" => None, + "Dacia" => Dacia, + "Tesla" => Tesla, + "BMW" => BMW, + "Mercedes" => Mercedes, + _ => throw new InvalidOperationException($"{key} is not a valid value for CarTypes") + }; + } + + /// Tries to create the instance matching . + /// The key to look up. + /// When this method returns , contains the matching instance; otherwise . + /// if a matching instance was found; otherwise . + public static bool TryCreate(string? key, [NotNullWhen(true)] out CarTypes? value) + { + value = key switch + { + "None" => None, + "Dacia" => Dacia, + "Tesla" => Tesla, + "BMW" => BMW, + "Mercedes" => Mercedes, + _ => null + }; + return value is not null; + } + + /// Tries to create the instance matching without allocating a string. + /// The key span to look up. + /// When this method returns , contains the matching instance; otherwise . + /// if a matching instance was found; otherwise . + public static bool TryCreate(ReadOnlySpan key, [NotNullWhen(true)] out CarTypes? value) + { + value = key switch + { + "None" => None, + "Dacia" => Dacia, + "Tesla" => Tesla, + "BMW" => BMW, + "Mercedes" => Mercedes, + _ => null + }; + return value is not null; + } + + /// Returns if is a valid enumeration value. + /// The key to check. + /// if the key is defined; otherwise . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsDefined(string? key) => TryCreate(key, out _); + + /// Returns if is a valid enumeration value without allocating a string. + /// The key span to check. + /// if the key is defined; otherwise . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsDefined(ReadOnlySpan key) => TryCreate(key, out _); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static CarTypes Parse(string s, IFormatProvider? provider) => Create(s); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryParse(string? s, IFormatProvider? provider, [NotNullWhen(true)] out CarTypes? result) => TryCreate(s, out result); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static CarTypes Parse(ReadOnlySpan s, IFormatProvider? provider) => Create(s.ToString()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, [NotNullWhen(true)] out CarTypes? result) => TryCreate(s, out result); + + /// Returns when 's key equals using ordinal string comparison. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(CarTypes? a, string? b) + => a is not null && b is not null && a.Key.Equals(b, StringComparison.Ordinal); + + /// Returns when 's key does not equal . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(CarTypes? a, string? b) => !(a == b); + + /// Implicitly converts the instance to its . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator string(CarTypes value) => value.Key; + + /// Explicitly converts the to a instance. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static explicit operator CarTypes(string key) => Create(key); + + /// Returns the key of this enumeration value. + /// The string. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override string ToString() => Key; + + /// + public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) + { + if (Key.AsSpan().TryCopyTo(destination)) + { + charsWritten = Key.Length; + return true; + } + charsWritten = 0; + return false; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public string ToString(string? format, IFormatProvider? provider) => Key; + + /// Returns the value corresponding to the current enumeration value. + /// Returned when the current value is . + /// Returned when the current value is . + /// Returned when the current value is . + /// Returned when the current value is . + /// Returned when the current value is . + /// The return type. + /// The matched value. + /// Thrown when no case matches. + public T Match(T onNone, T onDacia, T onTesla, T onBMW, T onMercedes) + { + return Key switch + { + "None" => onNone, + "Dacia" => onDacia, + "Tesla" => onTesla, + "BMW" => onBMW, + "Mercedes" => onMercedes, + _ => throw new InvalidOperationException($"Unhandled enumeration value: {Key}") + }; + } + + /// Invokes the function corresponding to the current value and returns its result. + /// Invoked when the current value is . + /// Invoked when the current value is . + /// Invoked when the current value is . + /// Invoked when the current value is . + /// Invoked when the current value is . + /// The return type. + /// The value returned by the matched function. + /// Thrown when no case matches. + public T Match(Func onNone, Func onDacia, Func onTesla, Func onBMW, Func onMercedes) + { + return Key switch + { + "None" => onNone(), + "Dacia" => onDacia(), + "Tesla" => onTesla(), + "BMW" => onBMW(), + "Mercedes" => onMercedes(), + _ => throw new InvalidOperationException($"Unhandled enumeration value: {Key}") + }; + } + + /// Invokes the function corresponding to the current value, passing , and returns its result. + /// The state to pass to the function. + /// Invoked when the current value is . + /// Invoked when the current value is . + /// Invoked when the current value is . + /// Invoked when the current value is . + /// Invoked when the current value is . + /// The return type. + /// The type of the state object. + /// The value returned by the matched function. + /// Thrown when no case matches. + public T Match(TState state, Func onNone, Func onDacia, Func onTesla, Func onBMW, Func onMercedes) + { + return Key switch + { + "None" => onNone(state), + "Dacia" => onDacia(state), + "Tesla" => onTesla(state), + "BMW" => onBMW(state), + "Mercedes" => onMercedes(state), + _ => throw new InvalidOperationException($"Unhandled enumeration value: {Key}") + }; + } + + /// Invokes the action corresponding to the current value. + /// Invoked when the current value is . + /// Invoked when the current value is . + /// Invoked when the current value is . + /// Invoked when the current value is . + /// Invoked when the current value is . + /// Thrown when no case matches. + public void Match(Action onNone, Action onDacia, Action onTesla, Action onBMW, Action onMercedes) + { + switch (Key) + { + case "None": onNone(); return; + case "Dacia": onDacia(); return; + case "Tesla": onTesla(); return; + case "BMW": onBMW(); return; + case "Mercedes": onMercedes(); return; + default: throw new InvalidOperationException($"Unhandled enumeration value: {Key}"); + } + } + + /// Invokes the action corresponding to the current value, passing . + /// The state to pass to the action. + /// Invoked when the current value is . + /// Invoked when the current value is . + /// Invoked when the current value is . + /// Invoked when the current value is . + /// Invoked when the current value is . + /// The type of the state object. + /// Thrown when no case matches. + public void Match(TState state, Action onNone, Action onDacia, Action onTesla, Action onBMW, Action onMercedes) + { + switch (Key) + { + case "None": onNone(state); return; + case "Dacia": onDacia(state); return; + case "Tesla": onTesla(state); return; + case "BMW": onBMW(state); return; + case "Mercedes": onMercedes(state); return; + default: throw new InvalidOperationException($"Unhandled enumeration value: {Key}"); + } + } +} + +``` + + + + +```csharp showLineNumbers +// +#nullable enable + +using System; + +namespace LinkDotNet.Enumeration; + +/// Specifies how static member names are derived from the string values. +internal enum Casing +{ + /// Converts each value to PascalCase (default). + PascalCase, + /// Uses the raw string value as the member name. + Preserve +} + +/// +/// Marks a partial class or partial record as a source-generated enumeration. +/// The generator emits: Key property, private constructor, static readonly fields, +/// All, Create, TryCreate, == / != operators, ToString, Match<T> and Match(Action). +/// +[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] +internal sealed class EnumerationAttribute : Attribute +{ + public string[] Values \{ get; } + public Casing MemberCasing \{ get; } + /// + /// When , a + /// is applied to the enumeration type and a \{TypeName}\}JsonConverter class is generated + /// that serializes and deserializes the type as its Key string using + /// . + /// + public bool GenerateJsonConverter \{ get; init; } + public EnumerationAttribute(params string[] values) => (Values, MemberCasing) = (values, Casing.PascalCase); + public EnumerationAttribute(Casing casing, params string[] values) => (Values, MemberCasing) = (values, casing); +} +``` + + + + +## Useful + +### Download Example (.NET C#) + +:::tip + +[Download Example project LinkDotNet.Enumeration ](/sources/LinkDotNet.Enumeration.zip) + +::: + + +### Share LinkDotNet.Enumeration + + + +https://ignatandrei.github.io/RSCG_Examples/v2/docs/LinkDotNet.Enumeration + + + diff --git a/v2/rscg_examples_site/docs/RSCG-Examples/index.md b/v2/rscg_examples_site/docs/RSCG-Examples/index.md index 2f09c0b34..86901ae2d 100644 --- a/v2/rscg_examples_site/docs/RSCG-Examples/index.md +++ b/v2/rscg_examples_site/docs/RSCG-Examples/index.md @@ -1,7 +1,7 @@ --- sidebar_position: 30 -title: 268 RSCG list by category -description: 268 RSCG list by category +title: 269 RSCG list by category +description: 269 RSCG list by category slug: /rscg-examples --- @@ -817,7 +817,7 @@ import DocCardList from '@theme/DocCardList'; ## Enum
- Expand Enum =>examples:14 + Expand Enum =>examples:15 @@ -888,6 +888,11 @@ import DocCardList from '@theme/DocCardList'; [Aigamo.MatchGenerator](/docs/Aigamo.MatchGenerator) + + + +[LinkDotNet.Enumeration](/docs/LinkDotNet.Enumeration) +
@@ -1972,6 +1977,8 @@ flowchart LR; Enum--> Aigamo.MatchGenerator((Aigamo.MatchGenerator)) + Enum--> LinkDotNet.Enumeration((LinkDotNet.Enumeration)) + Equals--> GeneratorEquals((GeneratorEquals)) Equals--> Equatable.Generator((Equatable.Generator)) diff --git a/v2/rscg_examples_site/docs/about.md b/v2/rscg_examples_site/docs/about.md index 043aecbc0..f54fb1847 100644 --- a/v2/rscg_examples_site/docs/about.md +++ b/v2/rscg_examples_site/docs/about.md @@ -6,7 +6,7 @@ title: About ## Content You will find here code examples -of 268 Roslyn Source Code Generator (RSCG) +of 269 Roslyn Source Code Generator (RSCG) that can be useful for you. That means, you will write more elegant and concise code - even if the generators code is not always nice to look. ## Are those examples ready for production? diff --git a/v2/rscg_examples_site/docs/indexRSCG.md b/v2/rscg_examples_site/docs/indexRSCG.md index fb5277db4..8aed8801a 100644 --- a/v2/rscg_examples_site/docs/indexRSCG.md +++ b/v2/rscg_examples_site/docs/indexRSCG.md @@ -7,9 +7,9 @@ slug: /List-of-RSCG import useBaseUrl from '@docusaurus/useBaseUrl'; -## 268 RSCG with examples in descending chronological order +## 269 RSCG with examples in descending chronological order -This is the list of 268 ( 16 from Microsoft) RSCG with examples +This is the list of 269 ( 16 from Microsoft) RSCG with examples [See by category](/docs/rscg-examples) [See as json](/exports/RSCG.json) [See as Excel](/exports/RSCG.xlsx) @@ -20,6 +20,7 @@ This is the list of 268 ( 16 from Microsoft) RSCG with examples | No | Name | Date | Category | | --------- | ----- | ---- | -------- | +|269| [LinkDotNet.Enumeration by Steven Giesel ](/docs/LinkDotNet.Enumeration)|2026-05-14 => 14 May 2026 | [Enum](/docs/Categories/Enum) | |268| [GenerateDispose by Itai Tzur ](/docs/GenerateDispose)|2026-05-13 => 13 May 2026 | [Disposer](/docs/Categories/Disposer) | |267| [Maestria.TypeProviders by Fábio Monteiro Naspolini ](/docs/Maestria.TypeProviders)|2026-04-09 => 09 April 2026 | [FilesToCode](/docs/Categories/FilesToCode) | |266| [Aigamo.MatchGenerator by Aigamo ](/docs/Aigamo.MatchGenerator)|2026-04-08 => 08 April 2026 | [Enum](/docs/Categories/Enum) | diff --git a/v2/rscg_examples_site/src/components/HomepageFeatures/index.js b/v2/rscg_examples_site/src/components/HomepageFeatures/index.js index 3b511c31e..984a353de 100644 --- a/v2/rscg_examples_site/src/components/HomepageFeatures/index.js +++ b/v2/rscg_examples_site/src/components/HomepageFeatures/index.js @@ -4,7 +4,7 @@ import styles from './styles.module.css'; const FeatureList = [ { -title: '268 Examples (16 from MSFT)', +title: '269 Examples (16 from MSFT)', Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default, description: ( <> diff --git a/v2/rscg_examples_site/static/exports/RSCG.json b/v2/rscg_examples_site/static/exports/RSCG.json index fbf36bac9..095f0f55e 100644 --- a/v2/rscg_examples_site/static/exports/RSCG.json +++ b/v2/rscg_examples_site/static/exports/RSCG.json @@ -2145,6 +2145,14 @@ "Source": "https://github.com/ItaiTzur76/GenerateDispose", "Category": "Disposer", "AddedOn": "2026-05-13T00:00:00" + }, + { + "Name": "LinkDotNet.Enumeration", + "Link": "https://ignatandrei.github.io/RSCG_Examples/v2/docs/LinkDotNet.Enumeration", + "NuGet": "https://www.nuget.org/packages/LinkDotNet.Enumeration/", + "Source": "https://github.com/linkdotnet/Enumeration", + "Category": "Enum", + "AddedOn": "2026-05-14T00:00:00" } ] } \ No newline at end of file diff --git a/v2/rscg_examples_site/static/exports/RSCG.xlsx b/v2/rscg_examples_site/static/exports/RSCG.xlsx index a1ac877bc..c76735e0c 100644 Binary files a/v2/rscg_examples_site/static/exports/RSCG.xlsx and b/v2/rscg_examples_site/static/exports/RSCG.xlsx differ diff --git a/v2/rscg_examples_site/static/sources/LinkDotNet.Enumeration.zip b/v2/rscg_examples_site/static/sources/LinkDotNet.Enumeration.zip new file mode 100644 index 000000000..e9af2c4ad Binary files /dev/null and b/v2/rscg_examples_site/static/sources/LinkDotNet.Enumeration.zip differ