diff --git a/README.md b/README.md index 604818b0a..0f958a9c7 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -# RSCG - 240 Examples of Roslyn Source Code Generators / 16 created by Microsoft / +# RSCG - 241 Examples of Roslyn Source Code Generators / 16 created by Microsoft / -The RSCG_Examples repository is a comprehensive documentation system that automatically processes and showcases 240 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 241 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 : 2025-11-09 => 09 November 2025 +## Latest Update : 2025-11-10 => 10 November 2025 If you want to see examples with code, please click ***[List V2](https://ignatandrei.github.io/RSCG_Examples/v2/docs/List-of-RSCG)*** @@ -12,7 +12,7 @@ If you want just those from Microsoft, please click ***[Microsoft](https://ignat If you want to see by category, please click ***[category](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples)*** or click any category below -[actor](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#actor) -[ai](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#ai) -[aop](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#aop) -[api](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#api) -[async](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#async) -[bitwise](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#bitwise) -[blazor](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#blazor) -[builder](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#builder) -[clone](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#clone) -[codetostring](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#codetostring) -[commandline](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#commandline) -[console](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#console) -[constructor](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#constructor) -[database](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#database) -[dependencyinjection](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#dependencyinjection) -[disposer](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#disposer) -[enhancementclass](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#enhancementclass) -[enhancementproject](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#enhancementproject) -[enum](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#enum) -[equals](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#equals) -[filestocode](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#filestocode) -[functionalprogramming](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#functionalprogramming) -[hangfire](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#hangfire) -[interface](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#interface) -[linq](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#linq) -[mapper](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#mapper) -[mediator](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#mediator) -[mixin](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#mixin) -[mvc](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#mvc) -[mvvm](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#mvvm) -[optimizer](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#optimizer) -[primitiveobsession](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#primitiveobsession) -[rx](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#rx) -[serializer](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#serializer) -[signalr](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#signalr) -[statemachine](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#statemachine) -[templating](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#templating) -[tests](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#tests) -[validator](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#validator) -[winapi](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#winapi) - +[actor](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#actor) -[ai](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#ai) -[aop](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#aop) -[api](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#api) -[async](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#async) -[bitwise](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#bitwise) -[blazor](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#blazor) -[builder](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#builder) -[clone](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#clone) -[codetostring](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#codetostring) -[commandline](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#commandline) -[console](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#console) -[constructor](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#constructor) -[database](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#database) -[decorator](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#decorator) -[dependencyinjection](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#dependencyinjection) -[disposer](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#disposer) -[enhancementclass](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#enhancementclass) -[enhancementproject](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#enhancementproject) -[enum](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#enum) -[equals](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#equals) -[filestocode](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#filestocode) -[functionalprogramming](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#functionalprogramming) -[hangfire](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#hangfire) -[interface](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#interface) -[linq](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#linq) -[mapper](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#mapper) -[mediator](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#mediator) -[mixin](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#mixin) -[mvc](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#mvc) -[mvvm](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#mvvm) -[optimizer](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#optimizer) -[primitiveobsession](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#primitiveobsession) -[rx](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#rx) -[serializer](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#serializer) -[signalr](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#signalr) -[statemachine](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#statemachine) -[templating](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#templating) -[tests](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#tests) -[validator](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#validator) -[winapi](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#winapi) - ## If you have a Roslyn Source Code Generator, please create an issue. @@ -24,8 +24,32 @@ If you want to be notified each time I add a new RSCG example , please click htt ## Content -Those are the 240 Roslyn Source Code Generators that I have tested you can see and download source code example. +Those are the 241 Roslyn Source Code Generators that I have tested you can see and download source code example. ( including 16 from Microsoft ) +### 241. [DecoratorGenerator](https://ignatandrei.github.io/RSCG_Examples/v2/docs/DecoratorGenerator) , in the [Decorator](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#decorator) category + +Generated on : 2025-11-10 => 10 November 2025 + +
+ Expand + + + +Author: Leopoldo Fu + +Source generator for decorator pattern boilerplate code in C#. + +When implementing the decorator pattern in C#, it requires adding boilerplate code for every interface that needs to support decorators, namely the abstract class. Boilerplate is tedious to write and error-prone. This source generator solves this problem by automatically generating the abstract class. It only needs to be told which interfaces it should generate the abstract class for. + +Nuget: [https://www.nuget.org/packages/DecoratorGenerator/](https://www.nuget.org/packages/DecoratorGenerator/) + + +Link: [https://ignatandrei.github.io/RSCG_Examples/v2/docs/DecoratorGenerator](https://ignatandrei.github.io/RSCG_Examples/v2/docs/DecoratorGenerator) + +Source: [https://github.com/CodingFlow/decorator-generator](https://github.com/CodingFlow/decorator-generator) + +
+ ### 240. [XmlCommentGenerator](https://ignatandrei.github.io/RSCG_Examples/v2/docs/XmlCommentGenerator) , in the [API](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#api) category Generated on : 2025-11-09 => 09 November 2025 diff --git a/later.md b/later.md index 115577914..e5031f2e8 100644 --- a/later.md +++ b/later.md @@ -1,6 +1,6 @@ # Just later -## Latest Update : 2025-11-09 => 09 November 2025 +## Latest Update : 2025-11-10 => 10 November 2025 diff --git a/v2/.tours/DecoratorGenerator.tour b/v2/.tours/DecoratorGenerator.tour new file mode 100644 index 000000000..4d36b0526 --- /dev/null +++ b/v2/.tours/DecoratorGenerator.tour @@ -0,0 +1,48 @@ + +{ + "$schema": "https://aka.ms/codetour-schema", + "title": "DecoratorGenerator", + "steps": + [ + { + "file": "rscg_examples/DecoratorGenerator/src/DecoratorDemo/DecoratorDemo.csproj", + "description": "First, we add Nuget [DecoratorGenerator](https://www.nuget.org/packages/DecoratorGenerator/) in csproj ", + "pattern": "DecoratorGenerator" + } + + ,{ + "file": "rscg_examples/DecoratorGenerator/src/DecoratorDemo/LogPerson.cs", + "description": "File LogPerson.cs ", + "pattern": "this is the code" + } + + ,{ + "file": "rscg_examples/DecoratorGenerator/src/DecoratorDemo/IPerson.cs", + "description": "File IPerson.cs ", + "pattern": "this is the code" + } + + ,{ + "file": "rscg_examples/DecoratorGenerator/src/DecoratorDemo/Person.cs", + "description": "File Person.cs ", + "pattern": "this is the code" + } + + ,{ + "file": "rscg_examples/DecoratorGenerator/src/DecoratorDemo/Program.cs", + "description": "File Program.cs \r\n>> dotnet run --project rscg_examples/DecoratorGenerator/src/DecoratorDemo/DecoratorDemo.csproj ", + "pattern": "this is the code" + } + + + ,{ + "file": "rscg_examples/DecoratorGenerator/src/DecoratorDemo/obj/GX/DecoratorGenerator/DecoratorGenerator.Main/PersonDecorator.generated.cs", + "description": "Generated File 1 from 1 : PersonDecorator.generated.cs ", + "line": 1 + } + + ], + + "ref": "main" + +} \ No newline at end of file diff --git a/v2/Generator/all.csv b/v2/Generator/all.csv index 0f9cb6cad..d7aedca9e 100644 --- a/v2/Generator/all.csv +++ b/v2/Generator/all.csv @@ -239,3 +239,4 @@ Nr,Key,Source,Category 238,TeCLI, https://github.com/tyevco/TeCLI,CommandLine 239,TUnit, https://github.com/thomhurst/TUnit,Tests 240,XmlCommentGenerator, https://github.com/dotnet/dotnet/,API +241,DecoratorGenerator, https://github.com/CodingFlow/decorator-generator,Decorator diff --git a/v2/GeneratorData/Category.cs b/v2/GeneratorData/Category.cs index 197fc23a9..637bb15c5 100644 --- a/v2/GeneratorData/Category.cs +++ b/v2/GeneratorData/Category.cs @@ -43,5 +43,6 @@ public enum Category RX=38, Mixin=39, Validator=40, + Decorator= 41 } diff --git a/v2/RSCGExamplesData/GeneratorDataRec.json b/v2/RSCGExamplesData/GeneratorDataRec.json index df066e2f1..67fbf0934 100644 --- a/v2/RSCGExamplesData/GeneratorDataRec.json +++ b/v2/RSCGExamplesData/GeneratorDataRec.json @@ -1453,5 +1453,11 @@ "Category":15, "dtStart": "2025-11-09T00:00:00", "show": true +}, +{ + "ID":"DecoratorGenerator", + "Category":41, + "dtStart": "2025-11-10T00:00:00", + "show": true } ] \ No newline at end of file diff --git a/v2/book/examples/DecoratorGenerator.html b/v2/book/examples/DecoratorGenerator.html new file mode 100644 index 000000000..5d791d843 --- /dev/null +++ b/v2/book/examples/DecoratorGenerator.html @@ -0,0 +1,71 @@ + +

RSCG nr 241 : DecoratorGenerator

+ +

Info

+Nuget : https://www.nuget.org/packages/DecoratorGenerator/ + +

You can find more details at : https://github.com/CodingFlow/decorator-generator

+ +

Author :Leopoldo Fu

+ +

Source: https://github.com/CodingFlow/decorator-generator

+ +

About

+ +adding decorator for classes/ interfaces + +

+ How to use +

+

+ Add reference to the DecoratorGenerator in the csproj +

+ + +

This was for me the starting code

+ +
+ I have coded the file Program.cs +
+ +
+ +
+ I have coded the file Person.cs +
+ +
+ +
+ I have coded the file IPerson.cs +
+ +
+ +
+ I have coded the file LogPerson.cs +
+ +
+

And here are the generated files

+ +
+ The file generated is PersonDecorator.generated.cs +
+ + +

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

+ + +

+ 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 82d089792..8df4e2e26 100644 --- a/v2/book/list.html +++ b/v2/book/list.html @@ -17,7 +17,7 @@

-This is the list of 240 RSCG with examples => +This is the list of 241 RSCG with examples =>

@@ -986,6 +986,10 @@

+ + + +
240 XmlCommentGenerator
241DecoratorGenerator
diff --git a/v2/book/pandocHTML.yaml b/v2/book/pandocHTML.yaml index 5eac068bd..953161eec 100644 --- a/v2/book/pandocHTML.yaml +++ b/v2/book/pandocHTML.yaml @@ -254,6 +254,7 @@ input-files: - examples/TeCLI.html - examples/TUnit.html - examples/XmlCommentGenerator.html +- examples/DecoratorGenerator.html # or you may use input-file: with a single value # defaults: diff --git a/v2/rscg_examples/DecoratorGenerator/description.json b/v2/rscg_examples/DecoratorGenerator/description.json new file mode 100644 index 000000000..6ed25bbfd --- /dev/null +++ b/v2/rscg_examples/DecoratorGenerator/description.json @@ -0,0 +1,22 @@ +{ + "generator":{ + "name":"DecoratorGenerator", + "nuget":[ + "https://www.nuget.org/packages/DecoratorGenerator/" + ], + "link":"https://github.com/CodingFlow/decorator-generator", + "author":"Leopoldo Fu", + "source":"https://github.com/CodingFlow/decorator-generator" + }, + "data":{ + "goodFor":["adding decorator for classes/ interfaces"], + "csprojDemo":"DecoratorDemo.csproj", + "csFiles":["Program.cs","Person.cs","IPerson.cs","LogPerson.cs"], + "excludeDirectoryGenerated":[""], + "includeAdditionalFiles":[""] + }, + "links":{ + "blog":"", + "video":"" + } +} \ No newline at end of file diff --git a/v2/rscg_examples/DecoratorGenerator/nuget.txt b/v2/rscg_examples/DecoratorGenerator/nuget.txt new file mode 100644 index 000000000..781c8942d --- /dev/null +++ b/v2/rscg_examples/DecoratorGenerator/nuget.txt @@ -0,0 +1,3 @@ +Source generator for decorator pattern boilerplate code in C#. + +When implementing the decorator pattern in C#, it requires adding boilerplate code for every interface that needs to support decorators, namely the abstract class. Boilerplate is tedious to write and error-prone. This source generator solves this problem by automatically generating the abstract class. It only needs to be told which interfaces it should generate the abstract class for. \ No newline at end of file diff --git a/v2/rscg_examples/DecoratorGenerator/readme.txt b/v2/rscg_examples/DecoratorGenerator/readme.txt new file mode 100644 index 000000000..c78b639b8 --- /dev/null +++ b/v2/rscg_examples/DecoratorGenerator/readme.txt @@ -0,0 +1,100 @@ +# Decorator Generator + +[![Nuget](https://img.shields.io/nuget/v/DecoratorGenerator)](https://www.nuget.org/packages/DecoratorGenerator) +![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/CodingFlow/decorator-generator/pull-request.yml) +[![Nuget](https://img.shields.io/nuget/dt/DecoratorGenerator)](https://www.nuget.org/packages/DecoratorGenerator) +[![GitHub Sponsors](https://img.shields.io/github/sponsors/CodingFlow)](https://github.com/sponsors/CodingFlow) + +Source generator for decorator pattern boilerplate code in C#. + +When implementing the [decorator pattern in C#](https://en.wikipedia.org/wiki/Decorator_pattern#C#), it requires adding boilerplate code for every interface that needs to support decorators, namely the abstract class. Boilerplate is tedious to write and error-prone. This source generator solves this problem by automatically generating the abstract class. It only needs to be told which interfaces it should generate the abstract class for. + +![decorator-pattern-uml](https://user-images.githubusercontent.com/3643313/220009438-a2ef1990-af1e-4b56-a5c9-b3f1aed2d80f.png) + +# Getting Started + +## Installation + +Add the library via NuGet to the project(s) that you want to auto-generate abstract decorator classes for: + +- Either via Project > Manage NuGet Packages... / Browse / search for decorator-generator / Install +- Or by running a command in the Package Manager Console + +```c# +Install-Package DecoratorGenerator +``` + +## Usage + +Add a `Decorate` attribute to the interface: + +```c# +using DecoratorGenerator; + +namespace SampleLibrary; + +[Decorate] +public interface ICat +{ + string Meow(); +} +``` + +Since this library is an [incremental source generator](https://github.com/dotnet/roslyn/blob/d8c21d64ca958840bdaa2898cb2324397dc57bbb/docs/features/incremental-generators.md), the abstract class should be generated after saving the changes to interface's file. The generated class will be named after the interface, but without the `I` prefix. In this case, since the interface is `ICat` the class will be `CatDecorator`. Then create your decorator class as usual: + +```c# +namespace SampleLibrary; + +public class BarkingCat : CatDecorator +{ + public BarkingCat(ICat cat) : base(cat) + { + + } + + public override string Meow() + { + return $"woof woof - {base.Meow()}"; + } +} + +``` + +Example usage of the decorator: + +```c# +using SampleLibrary; + +namespace SampleApp; + +partial class Program +{ + + static void Main(string[] args) + { + var cat = new BarkingCat(new Cat()); + var sound = cat.Meow(); + + Console.WriteLine(sound); + } + +} +``` + +# Configuration + +## List of Target Interfaces in a Config file + +To generate decorator abstract classes for third party interfaces, Decorator Generator will look for a struct named `WrapperList` and generate classes of the types in the fields of the `WrapperList`: + +```c# +using Amazon.DynamoDBv2.DataModel; + +public struct WrapperList +{ + // name the field whatever you want, the name isn't used, only the type is used. + IDynamoDBContext dynamoDBContext; +} +``` + +In this case, it will generate a class for `IDynamoDBContext` called `DynamoDBContextDecorator`. This feature will also work for your own interfaces if you prefer this approach instead of using the attribute. diff --git a/v2/rscg_examples/DecoratorGenerator/src/DecoratorDemo.slnx b/v2/rscg_examples/DecoratorGenerator/src/DecoratorDemo.slnx new file mode 100644 index 000000000..d4454ada2 --- /dev/null +++ b/v2/rscg_examples/DecoratorGenerator/src/DecoratorDemo.slnx @@ -0,0 +1,3 @@ + + + diff --git a/v2/rscg_examples/DecoratorGenerator/src/DecoratorDemo/DecoratorDemo.csproj b/v2/rscg_examples/DecoratorGenerator/src/DecoratorDemo/DecoratorDemo.csproj new file mode 100644 index 000000000..b9926b32e --- /dev/null +++ b/v2/rscg_examples/DecoratorGenerator/src/DecoratorDemo/DecoratorDemo.csproj @@ -0,0 +1,16 @@ + + + + Exe + net10.0 + enable + enable + + + true + $(BaseIntermediateOutputPath)\GX + + + + + diff --git a/v2/rscg_examples/DecoratorGenerator/src/DecoratorDemo/IPerson.cs b/v2/rscg_examples/DecoratorGenerator/src/DecoratorDemo/IPerson.cs new file mode 100644 index 000000000..bd48d8000 --- /dev/null +++ b/v2/rscg_examples/DecoratorGenerator/src/DecoratorDemo/IPerson.cs @@ -0,0 +1,16 @@ +using DecoratorGenerator; +using System; +using System.Collections.Generic; +using System.Text; + +namespace DecoratorDemo; + +[Decorate] +public interface IPerson +{ + public string FirstName { get; set; } + public string LastName { get; set; } + public string FullName(); + + public Task CalculateAgeAsync(DateTime birthDate); +} diff --git a/v2/rscg_examples/DecoratorGenerator/src/DecoratorDemo/LogPerson.cs b/v2/rscg_examples/DecoratorGenerator/src/DecoratorDemo/LogPerson.cs new file mode 100644 index 000000000..39bc8b2e7 --- /dev/null +++ b/v2/rscg_examples/DecoratorGenerator/src/DecoratorDemo/LogPerson.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace DecoratorDemo; + +internal class LogPerson : PersonDecorator +{ + public LogPerson(IPerson person) : base(person) + { + } + public override string FirstName + { + get + { + Console.WriteLine($"FirstName getter called, returning {base.FirstName}"); + return base.FirstName; + } + set + { + Console.WriteLine($"FirstName setter called, setting value to {value}"); + base.FirstName = value; + } + } + public override string FullName() + { + Console.WriteLine($"FullName() called for {FirstName} {LastName}" ); + return base.FullName(); + } + public override async Task CalculateAgeAsync(DateTime birthDate) + { + Console.WriteLine($"CalculateAgeAsync called with birthDate: {birthDate.ToShortDateString()}"); + return await base.CalculateAgeAsync(birthDate); + } +} diff --git a/v2/rscg_examples/DecoratorGenerator/src/DecoratorDemo/Person.cs b/v2/rscg_examples/DecoratorGenerator/src/DecoratorDemo/Person.cs new file mode 100644 index 000000000..f45175bae --- /dev/null +++ b/v2/rscg_examples/DecoratorGenerator/src/DecoratorDemo/Person.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace DecoratorDemo; + +internal class Person : IPerson +{ + public string FirstName { get; set; } = string.Empty; + public string LastName { get; set; } = string.Empty; + public string FullName() + { + return $"{FirstName} {LastName}"; + } + public async Task CalculateAgeAsync(DateTime birthDate) + { + await Task.Delay(100); // Simulate async work + var today = DateTime.Today; + var age = today.Year - birthDate.Year; + if (birthDate.Date > today.AddYears(-age)) age--; + return age; + } + +} \ No newline at end of file diff --git a/v2/rscg_examples/DecoratorGenerator/src/DecoratorDemo/Program.cs b/v2/rscg_examples/DecoratorGenerator/src/DecoratorDemo/Program.cs new file mode 100644 index 000000000..ed9943e3d --- /dev/null +++ b/v2/rscg_examples/DecoratorGenerator/src/DecoratorDemo/Program.cs @@ -0,0 +1,12 @@ +// See https://aka.ms/new-console-template for more information +using DecoratorDemo; + +Console.WriteLine("Hello, World!"); +IPerson person = new Person(); +person = new LogPerson(person); +person.FirstName = "Andrei"; +person.LastName = "Ignat"; +Console.WriteLine(person.FullName()); +var birthDate = new DateTime(1970, 4, 16); +var age = await person.CalculateAgeAsync(birthDate); +Console.WriteLine($"Age is {age}"); \ No newline at end of file diff --git a/v2/rscg_examples/DecoratorGenerator/video.json b/v2/rscg_examples/DecoratorGenerator/video.json new file mode 100644 index 000000000..c84b0378b --- /dev/null +++ b/v2/rscg_examples/DecoratorGenerator/video.json @@ -0,0 +1,39 @@ +{ + "scriptName": "DecoratorGenerator", + "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 DecoratorGenerator . adding decorator for classes/ interfaces ."}, +{"typeStep":"browser","arg":"https://www.nuget.org/packages/DecoratorGenerator/"}, +{"typeStep":"text","arg": "The whole example is here"}, +{"typeStep":"browser","arg":"https://ignatandrei.github.io/RSCG_Examples/v2/docs/DecoratorGenerator"}, +{"typeStep":"text","arg": "You can download the code from here"}, +{"typeStep":"browser","arg":"https://ignatandrei.github.io/RSCG_Examples/v2/docs/DecoratorGenerator#download-example-net--c-"}, +{"typeStep":"text","arg":"Here is the code downloaded "}, +{"typeStep":"exec","arg":"explorer.exe /select,D:\\gth\\RSCG_Examples\\v2\\Generator.sln"}, +{"typeStep":"text","arg": "So , let's start the project with Visual Studio Code "}, +{"typeStep":"stepvscode","arg": "-n D:\\gth\\RSCG_Examples\\v2"}, + +{"typeStep":"text","arg": "To use it ,you will put the Nuget DecoratorGenerator into the csproj "}, + +{"typeStep":"stepvscode","arg": "-r -g D:\\gth\\RSCG_Examples\\v2\\rscg_examples\\DecoratorGenerator\\src\\DecoratorDemo\\DecoratorDemo.csproj"}, + +{"typeStep":"text","arg": "And now I will show you an example of using DecoratorGenerator"}, + +{"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":"DecoratorDemo.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/DecoratorGenerator#download-example-net--c-", +SpeakTest=" "}, +{"typeStep":"waitseconds","arg":"30"}, +] +} diff --git a/v2/rscg_examples_site/docs/Categories/Decorator.md b/v2/rscg_examples_site/docs/Categories/Decorator.md new file mode 100644 index 000000000..b4c652c2d --- /dev/null +++ b/v2/rscg_examples_site/docs/Categories/Decorator.md @@ -0,0 +1,6 @@ +

Decorator

+ +Number RSCG: 1 + + 1 [DecoratorGenerator](/docs/DecoratorGenerator) [![Nuget](https://img.shields.io/nuget/dt/DecoratorGenerator?label=DecoratorGenerator)](https://www.nuget.org/packages/DecoratorGenerator/) ![GitHub Repo stars](https://img.shields.io/github/stars/CodingFlow/decorator-generator?style=social) 2025-11-10 + \ No newline at end of file diff --git a/v2/rscg_examples_site/docs/Categories/_PrimitiveDecorator.mdx b/v2/rscg_examples_site/docs/Categories/_PrimitiveDecorator.mdx new file mode 100644 index 000000000..3f0ae5f26 --- /dev/null +++ b/v2/rscg_examples_site/docs/Categories/_PrimitiveDecorator.mdx @@ -0,0 +1,7 @@ +### Category "Decorator" has the following generators: + + 1 [DecoratorGenerator](/docs/DecoratorGenerator) [![Nuget](https://img.shields.io/nuget/dt/DecoratorGenerator?label=DecoratorGenerator)](https://www.nuget.org/packages/DecoratorGenerator/) ![GitHub Repo stars](https://img.shields.io/github/stars/CodingFlow/decorator-generator?style=social) 2025-11-10 + +### See category + +[Decorator](/docs/Categories/Decorator) diff --git a/v2/rscg_examples_site/docs/RSCG-Examples/DecoratorGenerator.md b/v2/rscg_examples_site/docs/RSCG-Examples/DecoratorGenerator.md new file mode 100644 index 000000000..52452104e --- /dev/null +++ b/v2/rscg_examples_site/docs/RSCG-Examples/DecoratorGenerator.md @@ -0,0 +1,381 @@ +--- +sidebar_position: 2410 +title: 241 - DecoratorGenerator +description: adding decorator for classes/ interfaces +slug: /DecoratorGenerator +--- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import TOCInline from '@theme/TOCInline'; +import SameCategory from '../Categories/_PrimitiveDecorator.mdx'; + +# DecoratorGenerator by Leopoldo Fu + + + + +## NuGet / site data +[![Nuget](https://img.shields.io/nuget/dt/DecoratorGenerator?label=DecoratorGenerator)](https://www.nuget.org/packages/DecoratorGenerator/) +[![GitHub last commit](https://img.shields.io/github/last-commit/CodingFlow/decorator-generator?label=updated)](https://github.com/CodingFlow/decorator-generator) +![GitHub Repo stars](https://img.shields.io/github/stars/CodingFlow/decorator-generator?style=social) + +## Details + +### Info +:::info + +Name: **DecoratorGenerator** + +Source generator for decorator pattern boilerplate code in C#. + +When implementing the decorator pattern in C#, it requires adding boilerplate code for every interface that needs to support decorators, namely the abstract class. Boilerplate is tedious to write and error-prone. This source generator solves this problem by automatically generating the abstract class. It only needs to be told which interfaces it should generate the abstract class for. + +Author: Leopoldo Fu + +NuGet: +*https://www.nuget.org/packages/DecoratorGenerator/* + + +You can find more details at https://github.com/CodingFlow/decorator-generator + +Source: https://github.com/CodingFlow/decorator-generator + +::: + +### Author +:::note +Leopoldo Fu +![Alt text](https://github.com/CodingFlow.png) +::: + +### Original Readme +:::note + +# Decorator Generator + +[![Nuget](https://img.shields.io/nuget/v/DecoratorGenerator)](https://www.nuget.org/packages/DecoratorGenerator) +![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/CodingFlow/decorator-generator/pull-request.yml) +[![Nuget](https://img.shields.io/nuget/dt/DecoratorGenerator)](https://www.nuget.org/packages/DecoratorGenerator) +[![GitHub Sponsors](https://img.shields.io/github/sponsors/CodingFlow)](https://github.com/sponsors/CodingFlow) + +Source generator for decorator pattern boilerplate code in C#. + +When implementing the [decorator pattern in C#](https://en.wikipedia.org/wiki/Decorator_pattern#C#), it requires adding boilerplate code for every interface that needs to support decorators, namely the abstract class. Boilerplate is tedious to write and error-prone. This source generator solves this problem by automatically generating the abstract class. It only needs to be told which interfaces it should generate the abstract class for. + +![decorator-pattern-uml](https://user-images.githubusercontent.com/3643313/220009438-a2ef1990-af1e-4b56-a5c9-b3f1aed2d80f.png) + +# Getting Started + +## Installation + +Add the library via NuGet to the project(s) that you want to auto-generate abstract decorator classes for: + +- Either via Project > Manage NuGet Packages... / Browse / search for decorator-generator / Install +- Or by running a command in the Package Manager Console + +```c# +Install-Package DecoratorGenerator +``` + +## Usage + +Add a `Decorate` attribute to the interface: + +```c# +using DecoratorGenerator; + +namespace SampleLibrary; + +[Decorate] +public interface ICat +{ + string Meow(); +} +``` + +Since this library is an [incremental source generator](https://github.com/dotnet/roslyn/blob/d8c21d64ca958840bdaa2898cb2324397dc57bbb/docs/features/incremental-generators.md), the abstract class should be generated after saving the changes to interface's file. The generated class will be named after the interface, but without the `I` prefix. In this case, since the interface is `ICat` the class will be `CatDecorator`. Then create your decorator class as usual: + +```c# +namespace SampleLibrary; + +public class BarkingCat : CatDecorator +{ + public BarkingCat(ICat cat) : base(cat) + { + + } + + public override string Meow() + { + return $"woof woof - {base.Meow()}"; + } +} + +``` + +Example usage of the decorator: + +```c# +using SampleLibrary; + +namespace SampleApp; + +partial class Program +{ + + static void Main(string[] args) + { + var cat = new BarkingCat(new Cat()); + var sound = cat.Meow(); + + Console.WriteLine(sound); + } + +} +``` + +# Configuration + +## List of Target Interfaces in a Config file + +To generate decorator abstract classes for third party interfaces, Decorator Generator will look for a struct named `WrapperList` and generate classes of the types in the fields of the `WrapperList`: + +```c# +using Amazon.DynamoDBv2.DataModel; + +public struct WrapperList +{ + // name the field whatever you want, the name isn't used, only the type is used. + IDynamoDBContext dynamoDBContext; +} +``` + +In this case, it will generate a class for `IDynamoDBContext` called `DynamoDBContextDecorator`. This feature will also work for your own interfaces if you prefer this approach instead of using the attribute. + + +::: + +### About +:::note + +adding decorator for classes/ interfaces + + +::: + +## How to use + +### Example (source csproj, source files) + + + + + +This is the CSharp Project that references **DecoratorGenerator** +```xml showLineNumbers {14} + + + + Exe + net10.0 + enable + enable + + + true + $(BaseIntermediateOutputPath)\GX + + + + + + +``` + + + + + + This is the use of **DecoratorGenerator** in *Program.cs* + +```csharp showLineNumbers +// See https://aka.ms/new-console-template for more information +using DecoratorDemo; + +Console.WriteLine("Hello, World!"); +IPerson person = new Person(); +person = new LogPerson(person); +person.FirstName = "Andrei"; +person.LastName = "Ignat"; +Console.WriteLine(person.FullName()); +var birthDate = new DateTime(1970, 4, 16); +var age = await person.CalculateAgeAsync(birthDate); +Console.WriteLine($"Age is {age}"); +``` + + + + + This is the use of **DecoratorGenerator** in *Person.cs* + +```csharp showLineNumbers +using System; +using System.Collections.Generic; +using System.Text; + +namespace DecoratorDemo; + +internal class Person : IPerson +{ + public string FirstName \{ get; set; \} = string.Empty; + public string LastName \{ get; set; \} = string.Empty; + public string FullName() + { + return $"{FirstName} {LastName}"; + } + public async Task CalculateAgeAsync(DateTime birthDate) + { + await Task.Delay(100); // Simulate async work + var today = DateTime.Today; + var age = today.Year - birthDate.Year; + if (birthDate.Date > today.AddYears(-age)) age--; + return age; + } + +} +``` + + + + + This is the use of **DecoratorGenerator** in *IPerson.cs* + +```csharp showLineNumbers +using DecoratorGenerator; +using System; +using System.Collections.Generic; +using System.Text; + +namespace DecoratorDemo; + +[Decorate] +public interface IPerson +{ + public string FirstName \{ get; set; } + public string LastName \{ get; set; } + public string FullName(); + + public Task CalculateAgeAsync(DateTime birthDate); +} + +``` + + + + + This is the use of **DecoratorGenerator** in *LogPerson.cs* + +```csharp showLineNumbers +using System; +using System.Collections.Generic; +using System.Text; + +namespace DecoratorDemo; + +internal class LogPerson : PersonDecorator +{ + public LogPerson(IPerson person) : base(person) + { + } + public override string FirstName + { + get + { + Console.WriteLine($"FirstName getter called, returning {base.FirstName}"); + return base.FirstName; + } + set + { + Console.WriteLine($"FirstName setter called, setting value to {value}"); + base.FirstName = value; + } + } + public override string FullName() + { + Console.WriteLine($"FullName() called for {FirstName} {LastName}" ); + return base.FullName(); + } + public override async Task CalculateAgeAsync(DateTime birthDate) + { + Console.WriteLine($"CalculateAgeAsync called with birthDate: {birthDate.ToShortDateString()}"); + return await base.CalculateAgeAsync(birthDate); + } +} + +``` + + + + +### Generated Files + +Those are taken from $(BaseIntermediateOutputPath)\GX + + + + +```csharp showLineNumbers +// +#nullable restore +namespace DecoratorDemo; + +public abstract class PersonDecorator : IPerson +{ + private IPerson person; + + protected PersonDecorator(IPerson person) { + this.person = person; + } + + public virtual string FirstName \{ get => person.FirstName; set => person.FirstName = value; } + + public virtual string LastName \{ get => person.LastName; set => person.LastName = value; } + + public virtual string FullName() { + return person.FullName(); + } + + public virtual System.Threading.Tasks.Task CalculateAgeAsync(System.DateTime birthDate) { + return person.CalculateAgeAsync(birthDate); + } +} + +``` + + + + +## Useful + +### Download Example (.NET C#) + +:::tip + +[Download Example project DecoratorGenerator ](/sources/DecoratorGenerator.zip) + +::: + + +### Share DecoratorGenerator + + + +https://ignatandrei.github.io/RSCG_Examples/v2/docs/DecoratorGenerator + + + diff --git a/v2/rscg_examples_site/docs/RSCG-Examples/index.md b/v2/rscg_examples_site/docs/RSCG-Examples/index.md index f6f014b8c..5026666c3 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: 240 RSCG list by category -description: 240 RSCG list by category +title: 241 RSCG list by category +description: 241 RSCG list by category slug: /rscg-examples --- @@ -378,6 +378,18 @@ import DocCardList from '@theme/DocCardList'; +## Decorator +
+ + Expand Decorator =>examples:1 + + + +[DecoratorGenerator](/docs/DecoratorGenerator) + +
+ + ## DependencyInjection
@@ -1603,6 +1615,8 @@ flowchart LR; Database--> Unflat((Unflat)) + Decorator--> DecoratorGenerator((DecoratorGenerator)) + DependencyInjection--> AutoRegisterInject((AutoRegisterInject)) DependencyInjection--> Injectio((Injectio)) diff --git a/v2/rscg_examples_site/docs/about.md b/v2/rscg_examples_site/docs/about.md index 38ad69bee..947b96e0f 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 240 Roslyn Source Code Generator (RSCG) +of 241 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 7e49253d6..eec8a41b2 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'; -## 240 RSCG with examples in descending chronological order +## 241 RSCG with examples in descending chronological order -This is the list of 240 ( 16 from Microsoft) RSCG with examples +This is the list of 241 ( 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 240 ( 16 from Microsoft) RSCG with examples | No | Name | Date | Category | | --------- | ----- | ---- | -------- | +|241| [DecoratorGenerator by Leopoldo Fu ](/docs/DecoratorGenerator)|2025-11-10 => 10 November 2025 | [Decorator](/docs/Categories/Decorator) | |240| [XmlCommentGenerator by Microsoft ](/docs/XmlCommentGenerator)|2025-11-09 => 09 November 2025 | [API](/docs/Categories/API) | |239| [TUnit by Tom Longhurst ](/docs/TUnit)|2025-11-08 => 08 November 2025 | [Tests](/docs/Categories/Tests) | |238| [TeCLI by Tyler Coles ](/docs/TeCLI)|2025-11-07 => 07 November 2025 | [CommandLine](/docs/Categories/CommandLine) | diff --git a/v2/rscg_examples_site/src/components/HomepageFeatures/index.js b/v2/rscg_examples_site/src/components/HomepageFeatures/index.js index 61e6d20ca..043c9ea04 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: '240 Examples (16 from MSFT)', +title: '241 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 97ea4aaa1..e202fc845 100644 --- a/v2/rscg_examples_site/static/exports/RSCG.json +++ b/v2/rscg_examples_site/static/exports/RSCG.json @@ -1921,6 +1921,14 @@ "Source": "https://github.com/dotnet/dotnet/", "Category": "API", "AddedOn": "2025-11-09T00:00:00" + }, + { + "Name": "DecoratorGenerator", + "Link": "https://ignatandrei.github.io/RSCG_Examples/v2/docs/DecoratorGenerator", + "NuGet": "https://www.nuget.org/packages/DecoratorGenerator/", + "Source": "https://github.com/CodingFlow/decorator-generator", + "Category": "Decorator", + "AddedOn": "2025-11-10T00:00:00" } ] } \ No newline at end of file diff --git a/v2/rscg_examples_site/static/sources/DecoratorGenerator.zip b/v2/rscg_examples_site/static/sources/DecoratorGenerator.zip new file mode 100644 index 000000000..1224a140f Binary files /dev/null and b/v2/rscg_examples_site/static/sources/DecoratorGenerator.zip differ