diff --git a/README.md b/README.md index 19e54beb8..d3304c8eb 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -# RSCG - 286 Examples of Roslyn Source Code Generators / 16 created by Microsoft / +# RSCG - 287 Examples of Roslyn Source Code Generators / 16 created by Microsoft / -The RSCG_Examples repository is a comprehensive documentation system that automatically processes and showcases 286 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 287 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-08-27 => 27 August 2026 +## Latest Update : 2026-08-28 => 28 August 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 286 Roslyn Source Code Generators that I have tested you can see and download source code example. +Those are the 287 Roslyn Source Code Generators that I have tested you can see and download source code example. ( including 16 from Microsoft ) +### 287. [TrimItEasy](https://ignatandrei.github.io/RSCG_Examples/v2/docs/TrimItEasy) , in the [EnhancementClass](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#enhancementclass) category + +Generated on : 2026-08-28 => 28 August 2026 + +
+ Expand + + + +Author: Phong Nguyen + +Package Description + +Nuget: [https://www.nuget.org/packages/TrimItEasy/](https://www.nuget.org/packages/TrimItEasy/) + + +Link: [https://ignatandrei.github.io/RSCG_Examples/v2/docs/TrimItEasy](https://ignatandrei.github.io/RSCG_Examples/v2/docs/TrimItEasy) + +Source: [https://github.com/phongnguyend/TrimItEasy](https://github.com/phongnguyend/TrimItEasy) + +
+ ### 286. [SatorImaging.TDoubles](https://ignatandrei.github.io/RSCG_Examples/v2/docs/SatorImaging.TDoubles) , in the [Tests](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#tests) category Generated on : 2026-08-27 => 27 August 2026 diff --git a/later.md b/later.md index db0f7aed3..5c92ff14f 100644 --- a/later.md +++ b/later.md @@ -1,6 +1,6 @@ # Just later -## Latest Update : 2026-08-27 => 27 August 2026 +## Latest Update : 2026-08-28 => 28 August 2026 diff --git a/v2/.tours/TrimItEasy.tour b/v2/.tours/TrimItEasy.tour new file mode 100644 index 000000000..d3e903fb1 --- /dev/null +++ b/v2/.tours/TrimItEasy.tour @@ -0,0 +1,30 @@ + +{ + "$schema": "https://aka.ms/codetour-schema", + "title": "TrimItEasy", + "steps": + [ + { + "file": "rscg_examples/TrimItEasy/src/TrimDemo/TrimDemo.csproj", + "description": "First, we add Nuget [TrimItEasy](https://www.nuget.org/packages/TrimItEasy/) in csproj ", + "pattern": "TrimItEasy" + } + + ,{ + "file": "rscg_examples/TrimItEasy/src/TrimDemo/Program.cs", + "description": "File Program.cs \r\n>> dotnet run --project rscg_examples/TrimItEasy/src/TrimDemo/TrimDemo.csproj ", + "pattern": "this is the code" + } + + + ,{ + "file": "rscg_examples/TrimItEasy/src/TrimDemo/obj/GX/TrimItEasy.Generators/TrimItEasy.Generators.TrimmerSourceGenerator/PersonExtensions_FastTrimStrings.g.cs", + "description": "Generated File 1 from 1 : PersonExtensions_FastTrimStrings.g.cs ", + "line": 1 + } + + ], + + "ref": "main" + +} \ No newline at end of file diff --git a/v2/Generator/all.csv b/v2/Generator/all.csv index 8ed5de681..7a2489f21 100644 --- a/v2/Generator/all.csv +++ b/v2/Generator/all.csv @@ -285,3 +285,4 @@ Nr,Key,Source,Category 284,Pinecone.TypedPath, https://github.com/nickpinecone/typed-path,FilesToCode 285,PropertyResolvers, https://github.com/tombiddulph/PropertyResolvers,EnhancementProject 286,SatorImaging.TDoubles, https://github.com/sator-imaging/TDoubles,Tests +287,TrimItEasy, https://github.com/phongnguyend/TrimItEasy,EnhancementClass diff --git a/v2/RSCGExamplesData/GeneratorDataRec.json b/v2/RSCGExamplesData/GeneratorDataRec.json index 4e0c4b142..f5a56d8d8 100644 --- a/v2/RSCGExamplesData/GeneratorDataRec.json +++ b/v2/RSCGExamplesData/GeneratorDataRec.json @@ -1734,5 +1734,11 @@ "dtStart": "2026-08-27T00:00:00", "show": true } + ,{ + "ID":"TrimItEasy", + "Category": 5, + "dtStart": "2026-08-28T00:00:00", + "show": true + } ] \ No newline at end of file diff --git a/v2/book/examples/TrimItEasy.html b/v2/book/examples/TrimItEasy.html new file mode 100644 index 000000000..3094a5ec2 --- /dev/null +++ b/v2/book/examples/TrimItEasy.html @@ -0,0 +1,53 @@ + +

RSCG nr 287 : TrimItEasy

+ +

Info

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

You can find more details at : https://github.com/phongnguyend/TrimItEasy

+ +

Author :Phong Nguyen

+ +

Source: https://github.com/phongnguyend/TrimItEasy

+ +

About

+ +trimming eacg string from a class properties + +

+ How to use +

+

+ Add reference to the TrimItEasy in the csproj +

+ + +

This was for me the starting code

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

And here are the generated files

+ +
+ The file generated is PersonExtensions_FastTrimStrings.g.cs +
+ + +

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

+ + +

+ 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 158b1c9f2..d9219e0a0 100644 --- a/v2/book/list.html +++ b/v2/book/list.html @@ -17,7 +17,7 @@

-This is the list of 286 RSCG with examples => +This is the list of 287 RSCG with examples =>

@@ -1170,6 +1170,10 @@

+ + + +
286 SatorImaging.TDoubles
287TrimItEasy
diff --git a/v2/book/pandocHTML.yaml b/v2/book/pandocHTML.yaml index ebec810a2..9cfa09947 100644 --- a/v2/book/pandocHTML.yaml +++ b/v2/book/pandocHTML.yaml @@ -300,6 +300,7 @@ input-files: - examples/Pinecone.TypedPath.html - examples/PropertyResolvers.html - examples/SatorImaging.TDoubles.html +- examples/TrimItEasy.html # or you may use input-file: with a single value # defaults: diff --git a/v2/docFind.json b/v2/docFind.json index 4f3c3ee43..15638d3e5 100644 --- a/v2/docFind.json +++ b/v2/docFind.json @@ -1714,5 +1714,11 @@ "category": "Tests", "href": "/RSCG_Examples/v2/docs/SatorImaging.TDoubles/", "body": "Incremental source generator for creating mock wrapper classes." + }, + { + "title": "TrimItEasy", + "category": "EnhancementClass", + "href": "/RSCG_Examples/v2/docs/TrimItEasy/", + "body": "Package Description" } ] \ No newline at end of file diff --git a/v2/rscg_examples/TrimItEasy/description.json b/v2/rscg_examples/TrimItEasy/description.json new file mode 100644 index 000000000..e50e20f82 --- /dev/null +++ b/v2/rscg_examples/TrimItEasy/description.json @@ -0,0 +1,22 @@ +{ + "generator":{ + "name":"TrimItEasy", + "nuget":[ + "https://www.nuget.org/packages/TrimItEasy/" + ], + "link":"https://github.com/phongnguyend/TrimItEasy", + "author":"Phong Nguyen", + "source":"https://github.com/phongnguyend/TrimItEasy" + }, + "data":{ + "goodFor":["trimming eacg string from a class properties"], + "csprojDemo":"TrimDemo.csproj", + "csFiles":["Program.cs"], + "excludeDirectoryGenerated":[""], + "includeAdditionalFiles":[""] + }, + "links":{ + "blog":"", + "video":"" + } +} \ No newline at end of file diff --git a/v2/rscg_examples/TrimItEasy/nuget.txt b/v2/rscg_examples/TrimItEasy/nuget.txt new file mode 100644 index 000000000..882e74f60 --- /dev/null +++ b/v2/rscg_examples/TrimItEasy/nuget.txt @@ -0,0 +1 @@ +Package Description \ No newline at end of file diff --git a/v2/rscg_examples/TrimItEasy/readme.txt b/v2/rscg_examples/TrimItEasy/readme.txt new file mode 100644 index 000000000..4c39f2b43 --- /dev/null +++ b/v2/rscg_examples/TrimItEasy/readme.txt @@ -0,0 +1,286 @@ +# TrimItEasy + +A simple and efficient .NET library for automatically trimming string properties in complex objects. + +## Installation + +Install the package from NuGet: + +```bash +dotnet add package TrimItEasy +``` + +Or using the NuGet Package Manager in Visual Studio: +``` +Install-Package TrimItEasy +``` + +## Usage + +### Basic Usage + +Simply call the `TrimStrings()` extension method on any complex object: + +```csharp +using TrimItEasy; + +public class Person +{ + public string Name { get; set; } + + public string Email { get; set; } + + public Address HomeAddress { get; set; } +} + +var person = new Person +{ + Name = " John Doe ", + Email = " john@example.com ", + HomeAddress = new Address + { + Street = " 123 Main St ", + City = " New York " + } +}; + +// Trim all string properties +person.TrimStrings(); +``` + +### Skip Trimming Specific Properties + +Use the `[NotTrimmed]` attribute to prevent trimming of specific properties: + +```csharp +public class Address +{ + [NotTrimmed] + public string Street { get; set; } // This property will not be trimmed + + public string City { get; set; } // This property will be trimmed +} + +var address = new Address +{ + Street = " 123 Main St, Apt 4B ", // Will remain unchanged + City = " New York " // Will be trimmed to "New York" +}; + +address.TrimStrings(); +``` + +### Recursive Trimming + +By default, the library recursively trims all string properties in nested objects up to a maximum depth of 64 levels. You can customize this behavior using `TrimmingOptions`: + +```csharp +// Only trim top-level string properties (disable recursion) +person.TrimStrings(new TrimmingOptions { Recursive = false }); + +// Limit recursion to 2 levels of nested objects +person.TrimStrings(new TrimmingOptions { MaxDepth = 2 }); + +// Only trim the top-level object's string properties (no nested objects) +person.TrimStrings(new TrimmingOptions { MaxDepth = 0 }); +``` + +| Option | Type | Default | Description | +|-------------|--------|---------|------------------------------------------------------------------------------------------------------| +| `Recursive` | `bool` | `true` | Whether to trim strings in nested objects. When `false`, only top-level string properties are trimmed.| +| `MaxDepth` | `int` | `64` | Maximum depth for recursive trimming. `0` trims only top-level properties, `1` includes one level of nested objects, and so on. | + +### Supported Types + +The library works with: +- Complex objects with string properties +- Collections (Lists, Arrays, etc.) +- Nested objects +- Properties marked with `[NotTrimmed]` will be skipped + +### Limitations + +The library will throw an `ArgumentException` if you try to use it on: +- String types (use `string.Trim()` instead) +- Primitive types +- Enum types + +## Examples + +### Working with Collections + +```csharp +public class Company +{ + public string Name { get; set; } + + public List Employees { get; set; } +} + +public class Employee +{ + public string Name { get; set; } + + [NotTrimmed] + public string EmployeeId { get; set; } +} + +var company = new Company +{ + Name = " Acme Corp ", + Employees = new List + { + new Employee { Name = " John Doe ", EmployeeId = " E001 " }, + new Employee { Name = " Jane Smith ", EmployeeId = " E002 " } + } +}; + +company.TrimStrings(); +// Result: +// - company.Name = "Acme Corp" +// - company.Employees[0].Name = "John Doe" +// - company.Employees[0].EmployeeId = " E001 " (not trimmed due to [NotTrimmed]) +``` + +### Working with Nested Objects + +```csharp +public class Order +{ + public string OrderNumber { get; set; } + + public Customer Customer { get; set; } + + public List Items { get; set; } +} + +public class Customer +{ + public string Name { get; set; } + + [NotTrimmed] + public string PhoneNumber { get; set; } +} + +var order = new Order +{ + OrderNumber = " ORD-001 ", + Customer = new Customer + { + Name = " John Doe ", + PhoneNumber = " +1 (555) 123-4567 " + }, + Items = new List + { + new OrderItem { Description = " Product A " } + } +}; + +order.TrimStrings(); +// All string properties will be trimmed except Customer.PhoneNumber +``` + +### Source Generator (Zero Reflection) + +For maximum performance, TrimItEasy includes a source generator that produces optimized trimming code at compile time � no reflection at runtime. + +#### Installation + +Install both the core library and the source generator package: + +```bash +dotnet add package TrimItEasy +dotnet add package TrimItEasy.Generators +``` + +Or using the NuGet Package Manager in Visual Studio: +``` +Install-Package TrimItEasy +Install-Package TrimItEasy.Generators +``` + +> **Note:** The `TrimItEasy.Generators` package must be referenced as an analyzer. If you are referencing the project directly, use: +> ```xml +> OutputItemType="Analyzer" +> ReferenceOutputAssembly="false" /> +> ``` + +#### Usage + +1. **Define a `static partial` extension method** that takes your target type as a `this` parameter and returns `void`. +2. **Annotate it with `[GeneratedTrimming]`**. + +The source generator will implement the method body automatically. + +```csharp +using TrimItEasy; + +public class Person +{ + public string Name { get; set; } + public string Email { get; set; } + public Address HomeAddress { get; set; } + public List Phones { get; set; } +} + +public class Address +{ + public string Street { get; set; } + public string City { get; set; } +} + +public class Phone +{ + public string Type { get; set; } + public string Number { get; set; } +} + +// Define the partial method � the source generator fills in the implementation +public static partial class PersonExtensions +{ + [GeneratedTrimming] + public static partial void FastTrimStrings(this Person person); + + [GeneratedTrimming] + public static partial void FastTrimStringsWithOptions(this Person person, TrimmingOptions? options = null); +} +``` + +Then simply call the generated method: + +```csharp +var person = new Person +{ + Name = " John Doe ", + Email = " john@example.com ", + HomeAddress = new Address + { + Street = " 123 Main St ", + City = " New York " + }, + Phones = new List + { + new Phone { Type = " Mobile ", Number = " 123-456-7890 " } + } +}; + +person.FastTrimStrings(); +// All string properties are trimmed, including nested objects and collections +``` + +#### How It Works + +- The source generator analyzes the target type's property graph at compile time. +- It generates a dedicated trimming method that directly accesses each string property � no reflection involved. +- Nested objects and collections (`List`, arrays, etc.) are handled recursively. +- Properties marked with `[NotTrimmed]` are respected and skipped. +- Circular references are detected and handled safely using a visited set. + +## Contributing + +Contributions are welcome! Please feel free to submit a Pull Request. + +## License + +This project is licensed under the MIT License - see the LICENSE file for details. \ No newline at end of file diff --git a/v2/rscg_examples/TrimItEasy/src/TrimDemo.slnx b/v2/rscg_examples/TrimItEasy/src/TrimDemo.slnx new file mode 100644 index 000000000..1ce7224a4 --- /dev/null +++ b/v2/rscg_examples/TrimItEasy/src/TrimDemo.slnx @@ -0,0 +1,3 @@ + + + diff --git a/v2/rscg_examples/TrimItEasy/src/TrimDemo/Person.cs b/v2/rscg_examples/TrimItEasy/src/TrimDemo/Person.cs new file mode 100644 index 000000000..c61bf8e96 --- /dev/null +++ b/v2/rscg_examples/TrimItEasy/src/TrimDemo/Person.cs @@ -0,0 +1,18 @@ +using TrimItEasy; + +namespace TrimDemo; + +public partial class Person +{ + public int Id { get; set; } + + public string FirstName { get; set; } = string.Empty; + public string LastName { get; set; }= string.Empty; + +} + +public static partial class PersonExtensions +{ + [GeneratedTrimming] + public static partial void FastTrimStrings(this Person person); +} \ No newline at end of file diff --git a/v2/rscg_examples/TrimItEasy/src/TrimDemo/Program.cs b/v2/rscg_examples/TrimItEasy/src/TrimDemo/Program.cs new file mode 100644 index 000000000..f546179fc --- /dev/null +++ b/v2/rscg_examples/TrimItEasy/src/TrimDemo/Program.cs @@ -0,0 +1,7 @@ +using TrimDemo; + +Person p = new(); +p.FirstName = " Andrei "; +p.LastName = " Ignat "; +p.FastTrimStrings(); +Console.WriteLine(p.FirstName + " " + p.LastName); \ No newline at end of file diff --git a/v2/rscg_examples/TrimItEasy/src/TrimDemo/TrimDemo.csproj b/v2/rscg_examples/TrimItEasy/src/TrimDemo/TrimDemo.csproj new file mode 100644 index 000000000..534ec57af --- /dev/null +++ b/v2/rscg_examples/TrimItEasy/src/TrimDemo/TrimDemo.csproj @@ -0,0 +1,22 @@ + + + + Exe + net10.0 + enable + enable + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + true + $(BaseIntermediateOutputPath)\GX + + + diff --git a/v2/rscg_examples/TrimItEasy/video.json b/v2/rscg_examples/TrimItEasy/video.json new file mode 100644 index 000000000..f1bb23c9f --- /dev/null +++ b/v2/rscg_examples/TrimItEasy/video.json @@ -0,0 +1,39 @@ +{ + "scriptName": "TrimItEasy", + "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 TrimItEasy . trimming eacg string from a class properties ."}, +{"typeStep":"browser","arg":"https://www.nuget.org/packages/TrimItEasy/"}, +{"typeStep":"text","arg": "The whole example is here"}, +{"typeStep":"browser","arg":"https://ignatandrei.github.io/RSCG_Examples/v2/docs/TrimItEasy"}, +{"typeStep":"text","arg": "You can download the code from here"}, +{"typeStep":"browser","arg":"https://ignatandrei.github.io/RSCG_Examples/v2/docs/TrimItEasy#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 TrimItEasy into the csproj "}, + +{"typeStep":"stepvscode","arg": "-r -g D:\\gth\\RSCG_Examples\\v2\\rscg_examples\\TrimItEasy\\src\\TrimDemo\\TrimDemo.csproj"}, + +{"typeStep":"text","arg": "And now I will show you an example of using TrimItEasy"}, + +{"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":"TrimDemo.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/TrimItEasy#download-example-net--c-", +SpeakTest=" "}, +{"typeStep":"waitseconds","arg":"30"}, +] +} diff --git a/v2/rscg_examples_site/docs/Authors/Phong_Nguyen.md b/v2/rscg_examples_site/docs/Authors/Phong_Nguyen.md new file mode 100644 index 000000000..421735cfe --- /dev/null +++ b/v2/rscg_examples_site/docs/Authors/Phong_Nguyen.md @@ -0,0 +1,7 @@ +# Author : Phong Nguyen + +Number RSCG: 1 + + + 1 [TrimItEasy](/docs/TrimItEasy) [![Nuget](https://img.shields.io/nuget/dt/TrimItEasy?label=TrimItEasy)](https://www.nuget.org/packages/TrimItEasy/) ![GitHub Repo stars](https://img.shields.io/github/stars/phongnguyend/TrimItEasy?style=social) 2026-08-28 + diff --git a/v2/rscg_examples_site/docs/Categories/EnhancementClass.md b/v2/rscg_examples_site/docs/Categories/EnhancementClass.md index 51f96ad18..1a7b9e32e 100644 --- a/v2/rscg_examples_site/docs/Categories/EnhancementClass.md +++ b/v2/rscg_examples_site/docs/Categories/EnhancementClass.md @@ -1,6 +1,6 @@

EnhancementClass

-Number RSCG: 30 +Number RSCG: 31 1 [ApparatusAOT](/docs/ApparatusAOT) [![Nuget](https://img.shields.io/nuget/dt/Apparatus.AOT.Reflection?label=Apparatus.AOT.Reflection)](https://www.nuget.org/packages/Apparatus.AOT.Reflection/) ![GitHub Repo stars](https://img.shields.io/github/stars/byme8/Apparatus.AOT.Reflection?style=social) 2023-04-16 @@ -61,4 +61,6 @@ Number RSCG: 30 29 [TelemetryLogging](/docs/TelemetryLogging) [![Nuget](https://img.shields.io/nuget/dt/Microsoft.Extensions.Telemetry.Abstractions?label=Microsoft.Extensions.Telemetry.Abstractions)](https://www.nuget.org/packages/Microsoft.Extensions.Telemetry.Abstractions/) ![GitHub Repo stars](https://img.shields.io/github/stars/dotnet/extensions?style=social) 2023-11-30 30 [ThisClass](/docs/ThisClass) [![Nuget](https://img.shields.io/nuget/dt/ThisClass?label=ThisClass)](https://www.nuget.org/packages/ThisClass/) ![GitHub Repo stars](https://img.shields.io/github/stars/trympet/ThisClass?style=social) 2024-04-19 + + 31 [TrimItEasy](/docs/TrimItEasy) [![Nuget](https://img.shields.io/nuget/dt/TrimItEasy?label=TrimItEasy)](https://www.nuget.org/packages/TrimItEasy/) ![GitHub Repo stars](https://img.shields.io/github/stars/phongnguyend/TrimItEasy?style=social) 2026-08-28 \ No newline at end of file diff --git a/v2/rscg_examples_site/docs/Categories/_PrimitiveEnhancementClass.mdx b/v2/rscg_examples_site/docs/Categories/_PrimitiveEnhancementClass.mdx index a5701dca1..b4bc072cb 100644 --- a/v2/rscg_examples_site/docs/Categories/_PrimitiveEnhancementClass.mdx +++ b/v2/rscg_examples_site/docs/Categories/_PrimitiveEnhancementClass.mdx @@ -60,6 +60,8 @@ 30 [ThisClass](/docs/ThisClass) [![Nuget](https://img.shields.io/nuget/dt/ThisClass?label=ThisClass)](https://www.nuget.org/packages/ThisClass/) ![GitHub Repo stars](https://img.shields.io/github/stars/trympet/ThisClass?style=social) 2024-04-19 + 31 [TrimItEasy](/docs/TrimItEasy) [![Nuget](https://img.shields.io/nuget/dt/TrimItEasy?label=TrimItEasy)](https://www.nuget.org/packages/TrimItEasy/) ![GitHub Repo stars](https://img.shields.io/github/stars/phongnguyend/TrimItEasy?style=social) 2026-08-28 + ### See category [EnhancementClass](/docs/Categories/EnhancementClass) diff --git a/v2/rscg_examples_site/docs/RSCG-Examples/TrimItEasy.md b/v2/rscg_examples_site/docs/RSCG-Examples/TrimItEasy.md new file mode 100644 index 000000000..314ae2f27 --- /dev/null +++ b/v2/rscg_examples_site/docs/RSCG-Examples/TrimItEasy.md @@ -0,0 +1,529 @@ +--- +sidebar_position: 2870 +title: 287 - TrimItEasy +description: trimming eacg string from a class properties +slug: /TrimItEasy +--- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import TOCInline from '@theme/TOCInline'; +import SameCategory from '../Categories/_PrimitiveEnhancementClass.mdx'; + +# TrimItEasy by Phong Nguyen + + + + +## NuGet / site data +[![Nuget](https://img.shields.io/nuget/dt/TrimItEasy?label=TrimItEasy)](https://www.nuget.org/packages/TrimItEasy/) +[![GitHub last commit](https://img.shields.io/github/last-commit/phongnguyend/TrimItEasy?label=updated)](https://github.com/phongnguyend/TrimItEasy) +![GitHub Repo stars](https://img.shields.io/github/stars/phongnguyend/TrimItEasy?style=social) + +## Details + +### Info +:::info + +Name: **TrimItEasy** + +Package Description + +Author: Phong Nguyen + +NuGet: +*https://www.nuget.org/packages/TrimItEasy/* + + +You can find more details at https://github.com/phongnguyend/TrimItEasy + +Source: https://github.com/phongnguyend/TrimItEasy + +::: + +### Author +:::note +Phong Nguyen +![Alt text](https://github.com/phongnguyend.png) +::: + +## Original Readme +:::note + +### TrimItEasy + +A simple and efficient .NET library for automatically trimming string properties in complex objects. + +###### Installation + +Install the package from NuGet: + +```bash +dotnet add package TrimItEasy +``` + +Or using the NuGet Package Manager in Visual Studio: +``` +Install-Package TrimItEasy +``` + +###### Usage + +######### Basic Usage + +Simply call the `TrimStrings()` extension method on any complex object: + +```csharp +using TrimItEasy; + +public class Person +{ + public string Name \{ get; set; } + + public string Email \{ get; set; } + + public Address HomeAddress \{ get; set; } +} + +var person = new Person +{ + Name = " John Doe ", + Email = " john@example.com ", + HomeAddress = new Address + { + Street = " 123 Main St ", + City = " New York " + } +}; + +// Trim all string properties +person.TrimStrings(); +``` + +######### Skip Trimming Specific Properties + +Use the `[NotTrimmed]` attribute to prevent trimming of specific properties: + +```csharp +public class Address +{ + [NotTrimmed] + public string Street \{ get; set; \} // This property will not be trimmed + + public string City \{ get; set; \} // This property will be trimmed +} + +var address = new Address +{ + Street = " 123 Main St, Apt 4B ", // Will remain unchanged + City = " New York " // Will be trimmed to "New York" +}; + +address.TrimStrings(); +``` + +######### Recursive Trimming + +By default, the library recursively trims all string properties in nested objects up to a maximum depth of 64 levels. You can customize this behavior using `TrimmingOptions`: + +```csharp +// Only trim top-level string properties (disable recursion) +person.TrimStrings(new TrimmingOptions \{ Recursive = false }); + +// Limit recursion to 2 levels of nested objects +person.TrimStrings(new TrimmingOptions \{ MaxDepth = 2 }); + +// Only trim the top-level object's string properties (no nested objects) +person.TrimStrings(new TrimmingOptions \{ MaxDepth = 0 }); +``` + +| Option | Type | Default | Description | +|-------------|--------|---------|------------------------------------------------------------------------------------------------------| +| `Recursive` | `bool` | `true` | Whether to trim strings in nested objects. When `false`, only top-level string properties are trimmed.| +| `MaxDepth` | `int` | `64` | Maximum depth for recursive trimming. `0` trims only top-level properties, `1` includes one level of nested objects, and so on. | + +######### Supported Types + +The library works with: +- Complex objects with string properties +- Collections (Lists, Arrays, etc.) +- Nested objects +- Properties marked with `[NotTrimmed]` will be skipped + +######### Limitations + +The library will throw an `ArgumentException` if you try to use it on: +- String types (use `string.Trim()` instead) +- Primitive types +- Enum types + +###### Examples + +######### Working with Collections + +```csharp +public class Company +{ + public string Name \{ get; set; } + + public List Employees \{ get; set; } +} + +public class Employee +{ + public string Name \{ get; set; } + + [NotTrimmed] + public string EmployeeId \{ get; set; } +} + +var company = new Company +{ + Name = " Acme Corp ", + Employees = new List + { + new Employee \{ Name = " John Doe ", EmployeeId = " E001 " }, + new Employee \{ Name = " Jane Smith ", EmployeeId = " E002 " } + } +}; + +company.TrimStrings(); +// Result: +// - company.Name = "Acme Corp" +// - company.Employees[0].Name = "John Doe" +// - company.Employees[0].EmployeeId = " E001 " (not trimmed due to [NotTrimmed]) +``` + +######### Working with Nested Objects + +```csharp +public class Order +{ + public string OrderNumber \{ get; set; } + + public Customer Customer \{ get; set; } + + public List Items \{ get; set; } +} + +public class Customer +{ + public string Name \{ get; set; } + + [NotTrimmed] + public string PhoneNumber \{ get; set; } +} + +var order = new Order +{ + OrderNumber = " ORD-001 ", + Customer = new Customer + { + Name = " John Doe ", + PhoneNumber = " +1 (555) 123-4567 " + }, + Items = new List + { + new OrderItem \{ Description = " Product A " } + } +}; + +order.TrimStrings(); +// All string properties will be trimmed except Customer.PhoneNumber +``` + +######### Source Generator (Zero Reflection) + +For maximum performance, TrimItEasy includes a source generator that produces optimized trimming code at compile time � no reflection at runtime. + +########## Installation + +Install both the core library and the source generator package: + +```bash +dotnet add package TrimItEasy +dotnet add package TrimItEasy.Generators +``` + +Or using the NuGet Package Manager in Visual Studio: +``` +Install-Package TrimItEasy +Install-Package TrimItEasy.Generators +``` + +> **Note:** The `TrimItEasy.Generators` package must be referenced as an analyzer. If you are referencing the project directly, use: +> ```xml +> OutputItemType="Analyzer" +> ReferenceOutputAssembly="false" /> +> ``` + +########## Usage + +1. **Define a `static partial` extension method** that takes your target type as a `this` parameter and returns `void`. +2. **Annotate it with `[GeneratedTrimming]`**. + +The source generator will implement the method body automatically. + +```csharp +using TrimItEasy; + +public class Person +{ + public string Name \{ get; set; } + public string Email \{ get; set; } + public Address HomeAddress \{ get; set; } + public List Phones \{ get; set; } +} + +public class Address +{ + public string Street \{ get; set; } + public string City \{ get; set; } +} + +public class Phone +{ + public string Type \{ get; set; } + public string Number \{ get; set; } +} + +// Define the partial method � the source generator fills in the implementation +public static partial class PersonExtensions +{ + [GeneratedTrimming] + public static partial void FastTrimStrings(this Person person); + + [GeneratedTrimming] + public static partial void FastTrimStringsWithOptions(this Person person, TrimmingOptions? options = null); +} +``` + +Then simply call the generated method: + +```csharp +var person = new Person +{ + Name = " John Doe ", + Email = " john@example.com ", + HomeAddress = new Address + { + Street = " 123 Main St ", + City = " New York " + }, + Phones = new List + { + new Phone \{ Type = " Mobile ", Number = " 123-456-7890 " } + } +}; + +person.FastTrimStrings(); +// All string properties are trimmed, including nested objects and collections +``` + +########## How It Works + +- The source generator analyzes the target type's property graph at compile time. +- It generates a dedicated trimming method that directly accesses each string property � no reflection involved. +- Nested objects and collections (`List`, arrays, etc.) are handled recursively. +- Properties marked with `[NotTrimmed]` are respected and skipped. +- Circular references are detected and handled safely using a visited set. + +###### Contributing + +Contributions are welcome! Please feel free to submit a Pull Request. + +###### License + +This project is licensed under the MIT License - see the LICENSE file for details. + +::: + +### About +:::note + +trimming eacg string from a class properties + + +::: + +## How to use + +### Example (source csproj, source files) + + + + + +This is the CSharp Project that references **TrimItEasy** +```xml showLineNumbers {11} + + + + Exe + net10.0 + enable + enable + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + true + $(BaseIntermediateOutputPath)\GX + + + + +``` + + + + + + This is the use of **TrimItEasy** in *Program.cs* + +```csharp showLineNumbers +using TrimDemo; + +Person p = new(); +p.FirstName = " Andrei "; +p.LastName = " Ignat "; +p.FastTrimStrings(); +Console.WriteLine(p.FirstName + " " + p.LastName); +``` + + + + +### Generated Files + +Those are taken from $(BaseIntermediateOutputPath)\GX + + + + +```csharp showLineNumbers +// +#nullable enable + +using System.Collections; +using System.Collections.Generic; + +namespace TrimDemo; + +public static partial class PersonExtensions +{ + public static partial void FastTrimStrings(this global::TrimDemo.Person person) + { + var visited = new HashSet(ReferenceEqualityComparer.Instance); + TrimProperties_TrimDemo_Person(person, visited); + } + + private static void TrimProperties_TrimDemo_Person(global::TrimDemo.Person obj, HashSet visited) + { + if (obj == null || !visited.Add(obj)) + { + return; + } + + if (obj.FirstName != null) + { + obj.FirstName = obj.FirstName.Trim(); + } + + if (obj.LastName != null) + { + obj.LastName = obj.LastName.Trim(); + } + + } + + private static void TrimRecursive(object? obj, HashSet visited) + { + if (obj == null || obj is string) + { + return; + } + + var type = obj.GetType(); + if (type.IsPrimitive || type.IsEnum || type == typeof(decimal) || type == typeof(System.DateTime) || type == typeof(System.DateTimeOffset)) + { + return; + } + + if (!type.IsValueType && !visited.Add(obj)) + { + return; + } + + if (obj is global::TrimDemo.Person typed_TrimDemo_Person) + { + TrimProperties_TrimDemo_Person(typed_TrimDemo_Person, visited); + return; + } + + if (obj is IList list) + { + for (int i = 0; i < list.Count; i++) + { + if (list[i] is string s) + { + list[i] = s.Trim(); + } + else + { + TrimRecursive(list[i], visited); + } + } + return; + } + + if (obj is IEnumerable enumerable) + { + foreach (var item in enumerable) + { + if (item is not string) + { + TrimRecursive(item, visited); + } + } + return; + } + } + +} + +``` + + + + +## Useful + +### Download Example (.NET C#) + +:::tip + +[Download Example project TrimItEasy ](/sources/TrimItEasy.zip) + +::: + + +### Share TrimItEasy + + + +https://ignatandrei.github.io/RSCG_Examples/v2/docs/TrimItEasy + + + diff --git a/v2/rscg_examples_site/docs/RSCG-Examples/index.md b/v2/rscg_examples_site/docs/RSCG-Examples/index.md index 67311e430..f996a8660 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: 286 RSCG list by category -description: 286 RSCG list by category +title: 287 RSCG list by category +description: 287 RSCG list by category slug: /rscg-examples --- @@ -578,7 +578,7 @@ import DocCardList from '@theme/DocCardList'; ## EnhancementClass
- Expand EnhancementClass =>examples:30 + Expand EnhancementClass =>examples:31 @@ -729,6 +729,11 @@ import DocCardList from '@theme/DocCardList'; [NLog.Extensions.ThisClass](/docs/NLog.Extensions.ThisClass) + + + +[TrimItEasy](/docs/TrimItEasy) +
@@ -2011,6 +2016,8 @@ flowchart LR; EnhancementClass--> NLog.Extensions.ThisClass((NLog.Extensions.ThisClass)) + EnhancementClass--> TrimItEasy((TrimItEasy)) + EnhancementProject--> ThisAssembly((ThisAssembly)) EnhancementProject--> RSCG_TimeBombComment((RSCG_TimeBombComment)) diff --git a/v2/rscg_examples_site/docs/about.md b/v2/rscg_examples_site/docs/about.md index 3c5a30782..d3d8fbc0e 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 286 Roslyn Source Code Generator (RSCG) +of 287 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 9728d6125..c338f5100 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'; -## 286 RSCG with examples in descending chronological order +## 287 RSCG with examples in descending chronological order -This is the list of 286 ( 16 from Microsoft) RSCG with examples +This is the list of 287 ( 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 286 ( 16 from Microsoft) RSCG with examples | No | Name | Date | Category | | --------- | ----- | ---- | -------- | +|287| [TrimItEasy by Phong Nguyen ](/docs/TrimItEasy)|2026-08-28 => 28 August 2026 | [EnhancementClass](/docs/Categories/EnhancementClass) | |286| [SatorImaging.TDoubles by Sator Imaging ](/docs/SatorImaging.TDoubles)|2026-08-27 => 27 August 2026 | [Tests](/docs/Categories/Tests) | |285| [PropertyResolvers by Tom Biddulph ](/docs/PropertyResolvers)|2026-08-26 => 26 August 2026 | [EnhancementProject](/docs/Categories/EnhancementProject) | |284| [Pinecone.TypedPath by Nick Pinecone ](/docs/Pinecone.TypedPath)|2026-08-24 => 24 August 2026 | [FilesToCode](/docs/Categories/FilesToCode) | diff --git a/v2/rscg_examples_site/src/components/HomepageFeatures/index.js b/v2/rscg_examples_site/src/components/HomepageFeatures/index.js index e97576692..756d9e805 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: '286 Examples (16 from MSFT)', +title: '287 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 7ba28fd85..fc7520304 100644 --- a/v2/rscg_examples_site/static/exports/RSCG.json +++ b/v2/rscg_examples_site/static/exports/RSCG.json @@ -2289,6 +2289,14 @@ "Source": "https://github.com/sator-imaging/TDoubles", "Category": "Tests", "AddedOn": "2026-08-27T00:00:00" + }, + { + "Name": "TrimItEasy", + "Link": "https://ignatandrei.github.io/RSCG_Examples/v2/docs/TrimItEasy", + "NuGet": "https://www.nuget.org/packages/TrimItEasy/", + "Source": "https://github.com/phongnguyend/TrimItEasy", + "Category": "EnhancementClass", + "AddedOn": "2026-08-28T00: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 0bdeccf4b..e22a771f3 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/TrimItEasy.zip b/v2/rscg_examples_site/static/sources/TrimItEasy.zip new file mode 100644 index 000000000..de834650d Binary files /dev/null and b/v2/rscg_examples_site/static/sources/TrimItEasy.zip differ