diff --git a/README.md b/README.md index dcd256199..c1ce49854 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -# RSCG - 264 Examples of Roslyn Source Code Generators / 16 created by Microsoft / +# RSCG - 265 Examples of Roslyn Source Code Generators / 16 created by Microsoft / -The RSCG_Examples repository is a comprehensive documentation system that automatically processes and showcases 264 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 265 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-04-06 => 06 April 2026 +## Latest Update : 2026-04-07 => 07 April 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 264 Roslyn Source Code Generators that I have tested you can see and download source code example. +Those are the 265 Roslyn Source Code Generators that I have tested you can see and download source code example. ( including 16 from Microsoft ) +### 265. [lomapper](https://ignatandrei.github.io/RSCG_Examples/v2/docs/lomapper) , in the [Mapper](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#mapper) category + +Generated on : 2026-04-07 => 07 April 2026 + +
+ Expand + + + +Author: Junaid Desai + +LoMapper - Lightweight Object Mapper using compile-time source generation. Zero runtime reflection. + +Nuget: [https://www.nuget.org/packages/lomapper/](https://www.nuget.org/packages/lomapper/) + + +Link: [https://ignatandrei.github.io/RSCG_Examples/v2/docs/lomapper](https://ignatandrei.github.io/RSCG_Examples/v2/docs/lomapper) + +Source: [https://github.com/jdtoon/lomapper](https://github.com/jdtoon/lomapper) + +
+ ### 264. [Najlot.Audit.SourceGenerator](https://ignatandrei.github.io/RSCG_Examples/v2/docs/Najlot.Audit.SourceGenerator) , in the [Audit](https://ignatandrei.github.io/RSCG_Examples/v2/docs/rscg-examples#audit) category Generated on : 2026-04-06 => 06 April 2026 diff --git a/later.md b/later.md index 1d07d34f4..cbd956265 100644 --- a/later.md +++ b/later.md @@ -1,6 +1,6 @@ # Just later -## Latest Update : 2026-04-06 => 06 April 2026 +## Latest Update : 2026-04-07 => 07 April 2026 diff --git a/v2/.tours/lomapper.tour b/v2/.tours/lomapper.tour new file mode 100644 index 000000000..0ba60271f --- /dev/null +++ b/v2/.tours/lomapper.tour @@ -0,0 +1,72 @@ + +{ + "$schema": "https://aka.ms/codetour-schema", + "title": "lomapper", + "steps": + [ + { + "file": "rscg_examples/loMapper/src/mapperDemo/mapperDemo.csproj", + "description": "First, we add Nuget [lomapper](https://www.nuget.org/packages/lomapper/) in csproj ", + "pattern": "lomapper" + } + + ,{ + "file": "rscg_examples/loMapper/src/mapperDemo/PersonDTO.cs", + "description": "File PersonDTO.cs ", + "pattern": "this is the code" + } + + ,{ + "file": "rscg_examples/loMapper/src/mapperDemo/Person.cs", + "description": "File Person.cs ", + "pattern": "this is the code" + } + + ,{ + "file": "rscg_examples/loMapper/src/mapperDemo/Program.cs", + "description": "File Program.cs \r\n>> dotnet run --project rscg_examples/loMapper/src/mapperDemo/mapperDemo.csproj ", + "pattern": "this is the code" + } + + + ,{ + "file": "rscg_examples/loMapper/src/mapperDemo/obj/GX/LoMapper.Generator/LoMapper.Generator.LoMapperGenerator/UserMapper.g.cs", + "description": "Generated File 6 from 6 : UserMapper.g.cs ", + "line": 1 + } + + ,{ + "file": "rscg_examples/loMapper/src/mapperDemo/obj/GX/LightweightObjectMapper/LightweightObjectMapper.LightweightObjectMapperSourceGenerator/PredefinedSpecialTypeMapping.Generated.cs", + "description": "Generated File 5 from 6 : PredefinedSpecialTypeMapping.Generated.cs ", + "line": 1 + } + + ,{ + "file": "rscg_examples/loMapper/src/mapperDemo/obj/GX/LightweightObjectMapper/LightweightObjectMapper.LightweightObjectMapperSourceGenerator/LOMMapExtensions_mapperDemo_Person.g.cs", + "description": "Generated File 4 from 6 : LOMMapExtensions_mapperDemo_Person.g.cs ", + "line": 1 + } + + ,{ + "file": "rscg_examples/loMapper/src/mapperDemo/obj/GX/LightweightObjectMapper/LightweightObjectMapper.LightweightObjectMapperSourceGenerator/LightweightObjectMapper.PreCodes.PredefinedSpecialTypeMapping.cs", + "description": "Generated File 3 from 6 : LightweightObjectMapper.PreCodes.PredefinedSpecialTypeMapping.cs ", + "line": 1 + } + + ,{ + "file": "rscg_examples/loMapper/src/mapperDemo/obj/GX/LightweightObjectMapper/LightweightObjectMapper.LightweightObjectMapperSourceGenerator/LightweightObjectMapper.PreCodes.LightweightObjectMapperPreCodes.cs", + "description": "Generated File 2 from 6 : LightweightObjectMapper.PreCodes.LightweightObjectMapperPreCodes.cs ", + "line": 1 + } + + ,{ + "file": "rscg_examples/loMapper/src/mapperDemo/obj/GX/LightweightObjectMapper/LightweightObjectMapper.LightweightObjectMapperSourceGenerator/Extensions.Generated.cs", + "description": "Generated File 1 from 6 : Extensions.Generated.cs ", + "line": 1 + } + + ], + + "ref": "main" + +} \ No newline at end of file diff --git a/v2/Generator/MultiGeneratorV2.cs b/v2/Generator/MultiGeneratorV2.cs index de7821394..7eda18c97 100644 --- a/v2/Generator/MultiGeneratorV2.cs +++ b/v2/Generator/MultiGeneratorV2.cs @@ -119,7 +119,7 @@ public string[] SourceNoRSCG() { var text=await File.ReadAllTextAsync(nameFile); text = text.Replace("(/.github/", $"({d.Generator!.Source}/.github/"); - + text = text.Replace("(BenchmarkDotNet", $"({d.Generator!.Source}/BenchmarkDotNet"); text = text.Replace("(./BoolParameterGenerator.Github.Example/", $"({d.Generator!.Source}/BoolParameterGenerator.Github.Example/"); text = text.Replace("(docs/", $"({d.Generator!.Source}/docs/"); text = text.Replace("(img/", $"({d.Generator!.Source}/img/"); diff --git a/v2/Generator/all.csv b/v2/Generator/all.csv index fd4aba2ed..b82dc59c1 100644 --- a/v2/Generator/all.csv +++ b/v2/Generator/all.csv @@ -263,3 +263,4 @@ Nr,Key,Source,Category 262,SvgIconGenerator, https://github.com/helluvamatt/SvgIconGenerator,FilesToCode 263,TaggedEnum, https://github.com/al0rid4l/SixTatami,Enum 264,Najlot.Audit.SourceGenerator, https://github.com/najlot/Audit,Audit +265,loMapper, https://github.com/jdtoon/lomapper,Mapper diff --git a/v2/RSCGExamplesData/GeneratorDataRec.json b/v2/RSCGExamplesData/GeneratorDataRec.json index d77e379d9..f350fe844 100644 --- a/v2/RSCGExamplesData/GeneratorDataRec.json +++ b/v2/RSCGExamplesData/GeneratorDataRec.json @@ -1600,5 +1600,11 @@ "Category": 47, "dtStart": "2026-04-06T00:00:00", "show": true - } + }, + { + "ID":"lomapper", + "Category": 6, + "dtStart": "2026-04-07T00:00:00", + "show": true + } ] \ No newline at end of file diff --git a/v2/book/examples/lomapper.html b/v2/book/examples/lomapper.html new file mode 100644 index 000000000..f2c66b8fe --- /dev/null +++ b/v2/book/examples/lomapper.html @@ -0,0 +1,90 @@ + +

RSCG nr 265 : lomapper

+ +

Info

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

You can find more details at : https://github.com/jdtoon/lomapper

+ +

Author :Junaid Desai

+ +

Source: https://github.com/jdtoon/lomapper

+ +

About

+ +Generate mapping code at compile time using source generators. + +

+ How to use +

+

+ Add reference to the lomapper 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 PersonDto.cs +
+ +
+

And here are the generated files

+ +
+ The file generated is Extensions.Generated.cs +
+ + +
+ The file generated is LightweightObjectMapper.PreCodes.LightweightObjectMapperPreCodes.cs +
+ + +
+ The file generated is LightweightObjectMapper.PreCodes.PredefinedSpecialTypeMapping.cs +
+ + +
+ The file generated is LOMMapExtensions_mapperDemo_Person.g.cs +
+ + +
+ The file generated is PredefinedSpecialTypeMapping.Generated.cs +
+ + +
+ The file generated is UserMapper.g.cs +
+ + +

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

+ + +

+ 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 2500408e9..3ae5686f7 100644 --- a/v2/book/list.html +++ b/v2/book/list.html @@ -17,7 +17,7 @@

-This is the list of 264 RSCG with examples => +This is the list of 265 RSCG with examples =>

@@ -1082,6 +1082,10 @@

+ + + +
264 Najlot.Audit.SourceGenerator
265lomapper
diff --git a/v2/book/pandocHTML.yaml b/v2/book/pandocHTML.yaml index 395a64ef5..2288a1a35 100644 --- a/v2/book/pandocHTML.yaml +++ b/v2/book/pandocHTML.yaml @@ -278,6 +278,7 @@ input-files: - examples/SvgIconGenerator.html - examples/TaggedEnum.html - examples/Najlot.Audit.SourceGenerator.html +- examples/lomapper.html # or you may use input-file: with a single value # defaults: diff --git a/v2/rscg_examples/lomapper/description.json b/v2/rscg_examples/lomapper/description.json new file mode 100644 index 000000000..642aa692b --- /dev/null +++ b/v2/rscg_examples/lomapper/description.json @@ -0,0 +1,22 @@ +{ + "generator":{ + "name":"lomapper", + "nuget":[ + "https://www.nuget.org/packages/lomapper/" + ], + "link":"https://github.com/jdtoon/lomapper", + "author":"Junaid Desai", + "source":"https://github.com/jdtoon/lomapper" + }, + "data":{ + "goodFor":["Generate mapping code at compile time using source generators."], + "csprojDemo":"mapperDemo.csproj", + "csFiles":["Program.cs","Person.cs","PersonDTO.cs"], + "excludeDirectoryGenerated":[""], + "includeAdditionalFiles":[""] + }, + "links":{ + "blog":"", + "video":"" + } +} \ No newline at end of file diff --git a/v2/rscg_examples/lomapper/nuget.txt b/v2/rscg_examples/lomapper/nuget.txt new file mode 100644 index 000000000..b89b6baaf --- /dev/null +++ b/v2/rscg_examples/lomapper/nuget.txt @@ -0,0 +1 @@ +LoMapper - Lightweight Object Mapper using compile-time source generation. Zero runtime reflection. \ No newline at end of file diff --git a/v2/rscg_examples/lomapper/readme.txt b/v2/rscg_examples/lomapper/readme.txt new file mode 100644 index 000000000..510e6d17b --- /dev/null +++ b/v2/rscg_examples/lomapper/readme.txt @@ -0,0 +1,308 @@ +# LoMapper + +**A tiny, focused object mapper** — Generate mapping code at compile time using Roslyn Source Generators. + +[![NuGet](https://img.shields.io/nuget/v/LoMapper.svg)](https://www.nuget.org/packages/LoMapper/) +[![NuGet Downloads](https://img.shields.io/nuget/dt/LoMapper.svg)](https://www.nuget.org/packages/LoMapper/) +[![Build Status](https://github.com/jdtoon/lomapper/actions/workflows/ci.yml/badge.svg)](https://github.com/jdtoon/lomapper/actions/workflows/ci.yml) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![.NET](https://img.shields.io/badge/.NET-Standard%202.0+-purple.svg)](https://dotnet.microsoft.com/) +[![GitHub Stars](https://img.shields.io/github/stars/jdtoon/lomapper?style=social)](https://github.com/jdtoon/lomapper) + +## What is LoMapper? + +LoMapper is a small library that generates mapping code at compile time, saving you from writing repetitive property-by-property assignments by hand. + +**Benefits:** +- ✅ **Less boilerplate** — Stop writing manual property assignments +- ✅ **Compile-time safety** — Catch mapping issues during build, not at runtime +- ✅ **Zero runtime overhead** — No reflection, no scanning, just generated code +- ✅ **Debuggable** — F12 into generated code like it's your own +- ✅ **Simple** — Just add attributes to partial classes + +## Quick Start + +### Installation + +```bash +dotnet add package LoMapper +``` + +### Basic Usage + +```csharp +using LoMapper; + +// 1. Define your types +public class UserEntity +{ + public int Id { get; set; } + public string Name { get; set; } + public string Email { get; set; } +} + +public class UserDto +{ + public int Id { get; set; } + public string Name { get; set; } + public string Email { get; set; } +} + +// 2. Create a mapper +[Mapper] +public partial class UserMapper +{ + public partial UserDto Map(UserEntity entity); +} + +// 3. Use it +var mapper = new UserMapper(); +var dto = mapper.Map(entity); +``` + +That's it! The `Map` method is generated at compile time with property-by-property assignment. + +## Features + +### Property Mapping +Properties are matched by name (case-insensitive): + +```csharp +public class Source { public int ID { get; set; } } +public class Target { public int Id { get; set; } } // ✅ Matched +``` + +### Custom Property Mapping +Rename properties or apply transforms: + +```csharp +[Mapper] +public partial class UserMapper +{ + [MapProperty("FirstName", "FullName")] + [MapProperty("BirthDate", "Age", Transform = nameof(CalculateAge))] + public partial UserDto Map(UserEntity entity); + + private int CalculateAge(DateTime birthDate) + => DateTime.Today.Year - birthDate.Year; +} +``` + +### Ignore Properties +Skip properties you don't want mapped: + +```csharp +[Mapper] +public partial class UserMapper +{ + [MapIgnore("InternalId")] + [MapIgnore("CacheKey")] + public partial UserDto Map(UserEntity entity); +} +``` + +### Flatten Properties +Map nested object properties to flat target properties: + +```csharp +[Mapper] +public partial class UserMapper +{ + [FlattenProperty("Address.City", nameof(UserDto.AddressCity))] + [FlattenProperty("Address.ZipCode", nameof(UserDto.AddressZipCode))] + public partial UserDto Map(UserEntity entity); +} +``` + +Features: +- ✅ Deep nesting support (e.g., `Order.Customer.Address.City`) +- ✅ Null-safe navigation (`?.`) automatically generated +- ✅ Type-safe with compile-time validation +- ✅ Works with both reference and value types +- ✅ Combine with `[MapProperty]` and `[MapIgnore]` + +### Lifecycle Hooks (BeforeMap / AfterMap) +Run code before or after mapping to validate inputs, set defaults, or audit results: + +```csharp +[Mapper] +public partial class UserMapper +{ + [BeforeMap(nameof(ValidateUser))] + [AfterMap(nameof(AuditUser))] + public partial UserDto Map(UserEntity entity); + + private void ValidateUser(UserEntity entity) + { + if (string.IsNullOrWhiteSpace(entity.Email)) throw new InvalidOperationException("Email required"); + } + + private void AuditUser(UserDto dto) => dto.Tags = dto.Tags.Append("mapped").ToArray(); +} +``` + +Hooks execute in order: `BeforeMap` runs before object creation and property assignments; `AfterMap` runs after the target is fully constructed (including constructor-based mappings). + +### Nested Objects +For nested objects, declare explicit mapper methods: + +```csharp +[Mapper] +public partial class OrderMapper +{ + public partial OrderDto Map(OrderEntity entity); + public partial CustomerDto Map(CustomerEntity entity); // Used for nested Customer + public partial AddressDto Map(AddressEntity entity); // Used for nested Address +} +``` + +### Collections +Full support for collections — `List`, `IEnumerable`, `Dictionary`, `HashSet`, and arrays: + +```csharp +public class Source { public List Items { get; set; } } +public class Target { public List Items { get; set; } } // ✅ Auto-mapped +``` + +### Circular Reference Detection +LoMapper detects mapper graphs that contain cycles and stops the build with diagnostic `LOM010` so you can break the loop early. + +```csharp +[Mapper] +public partial class CircularMapper +{ + public partial TargetA Map(SourceA source); + public partial TargetB Map(SourceB source); +} + +public class SourceA { public SourceB? Child { get; set; } } +public class SourceB { public SourceA? Parent { get; set; } } + +public class TargetA { public TargetB? Child { get; set; } } +public class TargetB { public TargetA? Parent { get; set; } } +``` + +Mapping these types produces LOM010 describing the cycle. Break one side (e.g., ignore a property or change the DTO shape) to proceed. + +## Compile-Time Diagnostics + +LoMapper catches mapping issues **before your code runs**: + +| Code | Severity | Description | +|------|----------|-------------| +| LOM001 | ⚠️ Warning | Target property has no matching source property | +| LOM002 | ❌ Error | Property types are incompatible | +| LOM003 | ❌ Error | Nested object requires mapper method | +| LOM004 | ❌ Error | Invalid transform method signature | +| LOM005 | ❌ Error | Source property not found | +| LOM006 | ❌ Error | Target property not found | +| LOM007 | ❌ Error | Invalid flatten property path | +| LOM008 | ❌ Error | Flatten target property not found | +| LOM009 | ❌ Error | Flatten type mismatch | +| LOM010 | ❌ Error | Circular reference detected in mapper graph | + +Example: +```csharp +public class Source { public int Id { get; set; } } +public class Target { public int Id { get; set; } public string Extra { get; set; } } + +// ⚠️ LOM001: Target property 'Extra' has no matching source property +``` + +## Benchmarks + +**Performance** + +LoMapper generates efficient code that performs well. Benchmark results mapping 10,000 objects: + +| Method | Mean | Memory | +|------------|------------|-----------| +| **LoMapper** | **174 μs** | 781 KB | +| Manual | 208 μs | 781 KB | + +*LoMapper matches the performance and memory characteristics of hand-written mapping code.* + +The generated code uses straightforward property assignments with no reflection or runtime overhead. For most applications, the performance is more than sufficient and comparable to writing the mappings yourself. + +
+Full Benchmark Details (Click to expand) + +Tested on Intel Core i7-10870H, .NET 8.0.23, Windows 11 using BenchmarkDotNet v0.14.0. + +**100 items:** 1.67 μs +**1,000 items:** 15.5 μs +**10,000 items:** 174 μs + +The generated code produces clean IL that the JIT compiler can optimize effectively. Zero allocations beyond the mapped objects themselves. + +[Full Results](BenchmarkDotNet.Artifacts/results/) +
+```bash +cd benchmarks/LoMapper.Benchmarks +dotnet run -c Release +``` + +## View Generated Code + +Enable generated file output in your `.csproj`: + +```xml + + true + +``` + +Find generated files in: `obj/GeneratedFiles/LoMapper.Generator/` + +## Comparison + +| Feature | LoMapper | Manual Code | +|---------|:--------:|:-----------:| +| **Performance (10K items)** | **174 μs** | 208 μs | +| Memory overhead | **0%** | - | +| Compile-time generation | ✅ | N/A | +| Zero runtime reflection | ✅ | ✅ | +| Compile-time error detection | ✅ | ✅ | +| IntelliSense support | ✅ | ✅ | +| Nested object mapping | ✅ | ✅ | +| Collection mapping | ✅ | ✅ | +| Custom transforms | ✅ | ✅ | +| Flattening/unflattening | ✅ v0.3 | Manual | +| Projection (IQueryable) | 🔜 v1.0 | Manual | + +## Why Use LoMapper? + +**vs Writing Mappings Manually:** +- Less repetitive code to write and maintain +- Compile-time validation catches errors early +- Automatic updates when models change +- Similar or better performance + +**When LoMapper Might Help:** +- You have many DTOs to map +- You want compile-time safety without runtime cost +- You prefer code generation over reflection +- You like seeing exactly what code runs (F12 into generated code) + +**Current Limitations:** +- Expression projection for IQueryable not yet supported (planned for v1.0) +- Some advanced mapping scenarios may need manual code + +LoMapper is a focused tool that does one thing well: generate simple, efficient mapping code. It's meant to complement your toolkit, not replace everything else. + +## Requirements + +- .NET Standard 2.0+ (runs on .NET Core 3.1+, .NET 5+, .NET Framework 4.7.2+) +- C# 9.0+ (for partial methods) + +## Contributing + +Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) first. + +## License + +MIT License - see [LICENSE](LICENSE) for details. + +--- + +**LoMapper** — A tiny tool to help you write less mapping code. diff --git a/v2/rscg_examples/lomapper/src/mapperDemo.slnx b/v2/rscg_examples/lomapper/src/mapperDemo.slnx new file mode 100644 index 000000000..6712d745c --- /dev/null +++ b/v2/rscg_examples/lomapper/src/mapperDemo.slnx @@ -0,0 +1,3 @@ + + + diff --git a/v2/rscg_examples/lomapper/src/mapperDemo/Person.cs b/v2/rscg_examples/lomapper/src/mapperDemo/Person.cs new file mode 100644 index 000000000..c1c18c040 --- /dev/null +++ b/v2/rscg_examples/lomapper/src/mapperDemo/Person.cs @@ -0,0 +1,8 @@ + +public partial class Person +{ + public int ID { get; set; } + public string? FirstName { get; set; } + public string? LastName { get; set; } +} + diff --git a/v2/rscg_examples/lomapper/src/mapperDemo/PersonDTO.cs b/v2/rscg_examples/lomapper/src/mapperDemo/PersonDTO.cs new file mode 100644 index 000000000..c75f8c522 --- /dev/null +++ b/v2/rscg_examples/lomapper/src/mapperDemo/PersonDTO.cs @@ -0,0 +1,24 @@ +using LoMapper; +using System.Xml.Serialization; + +namespace mapperDemo; +public partial struct PersonDTO +{ + public string? FirstName { get; set; } + public string? LastName { get; set; } + + public string FullName { + get + { + return FirstName + " " + LastName; + } + } +} + + +[Mapper] +public partial class UserMapper +{ + [MapIgnore(nameof(Person.ID))] + public partial PersonDTO Map(Person entity); +} \ No newline at end of file diff --git a/v2/rscg_examples/lomapper/src/mapperDemo/Program.cs b/v2/rscg_examples/lomapper/src/mapperDemo/Program.cs new file mode 100644 index 000000000..f6e93b0dc --- /dev/null +++ b/v2/rscg_examples/lomapper/src/mapperDemo/Program.cs @@ -0,0 +1,6 @@ +using mapperDemo; +var p=new Person(); +p.FirstName = "Andrei"; +p.LastName = "Ignat"; +PersonDTO dto= new UserMapper().Map(p); +Console.WriteLine(dto.FullName); diff --git a/v2/rscg_examples/lomapper/src/mapperDemo/mapperDemo.csproj b/v2/rscg_examples/lomapper/src/mapperDemo/mapperDemo.csproj new file mode 100644 index 000000000..b00e8cc03 --- /dev/null +++ b/v2/rscg_examples/lomapper/src/mapperDemo/mapperDemo.csproj @@ -0,0 +1,24 @@ + + + + Exe + net10.0 + enable + enable + + + + true + $(BaseIntermediateOutputPath)\GX + + + + + + + + + + + + diff --git a/v2/rscg_examples/lomapper/video.json b/v2/rscg_examples/lomapper/video.json new file mode 100644 index 000000000..b0de1c1eb --- /dev/null +++ b/v2/rscg_examples/lomapper/video.json @@ -0,0 +1,39 @@ +{ + "scriptName": "lomapper", + "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 lomapper . Generate mapping code at compile time using source generators. ."}, +{"typeStep":"browser","arg":"https://www.nuget.org/packages/lomapper/"}, +{"typeStep":"text","arg": "The whole example is here"}, +{"typeStep":"browser","arg":"https://ignatandrei.github.io/RSCG_Examples/v2/docs/lomapper"}, +{"typeStep":"text","arg": "You can download the code from here"}, +{"typeStep":"browser","arg":"https://ignatandrei.github.io/RSCG_Examples/v2/docs/lomapper#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 lomapper into the csproj "}, + +{"typeStep":"stepvscode","arg": "-r -g D:\\gth\\RSCG_Examples\\v2\\rscg_examples\\loMapper\\src\\mapperDemo\\mapperDemo.csproj"}, + +{"typeStep":"text","arg": "And now I will show you an example of using lomapper"}, + +{"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":"mapperDemo.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/lomapper#download-example-net--c-", +SpeakTest=" "}, +{"typeStep":"waitseconds","arg":"30"}, +] +} diff --git a/v2/rscg_examples_site/docs/Authors/Junaid_Desai.md b/v2/rscg_examples_site/docs/Authors/Junaid_Desai.md new file mode 100644 index 000000000..deafbe0b9 --- /dev/null +++ b/v2/rscg_examples_site/docs/Authors/Junaid_Desai.md @@ -0,0 +1,7 @@ +# Author : Junaid Desai + +Number RSCG: 1 + + + 1 [lomapper](/docs/lomapper) [![Nuget](https://img.shields.io/nuget/dt/lomapper?label=lomapper)](https://www.nuget.org/packages/lomapper/) ![GitHub Repo stars](https://img.shields.io/github/stars/jdtoon/lomapper?style=social) 2026-04-07 + diff --git a/v2/rscg_examples_site/docs/Categories/Mapper.md b/v2/rscg_examples_site/docs/Categories/Mapper.md index bdb6fe82e..1b7f8753b 100644 --- a/v2/rscg_examples_site/docs/Categories/Mapper.md +++ b/v2/rscg_examples_site/docs/Categories/Mapper.md @@ -1,6 +1,6 @@

Mapper

-Number RSCG: 9 +Number RSCG: 10 1 [AutoDTO](/docs/AutoDTO) [![Nuget](https://img.shields.io/nuget/dt/AutoDTO?label=AutoDTO)](https://www.nuget.org/packages/AutoDTO/) ![GitHub Repo stars](https://img.shields.io/github/stars/Ohorodnikov/AutoDto?style=social) 2023-08-24 @@ -12,11 +12,13 @@ Number RSCG: 9 5 [LightweightObjectMapper](/docs/LightweightObjectMapper) [![Nuget](https://img.shields.io/nuget/dt/LightweightObjectMapper?label=LightweightObjectMapper)](https://www.nuget.org/packages/LightweightObjectMapper/) ![GitHub Repo stars](https://img.shields.io/github/stars/stratosblue/LightweightObjectMapper?style=social) 2024-09-18 - 6 [MagicMap](/docs/MagicMap) [![Nuget](https://img.shields.io/nuget/dt/MagicMap?label=MagicMap)](https://www.nuget.org/packages/MagicMap/) ![GitHub Repo stars](https://img.shields.io/github/stars/bramerdaniel/MagicMap?style=social) 2023-10-08 + 6 [lomapper](/docs/lomapper) [![Nuget](https://img.shields.io/nuget/dt/lomapper?label=lomapper)](https://www.nuget.org/packages/lomapper/) ![GitHub Repo stars](https://img.shields.io/github/stars/jdtoon/lomapper?style=social) 2026-04-07 - 7 [mapperly](/docs/mapperly) [![Nuget](https://img.shields.io/nuget/dt/Riok.Mapperly?label=Riok.Mapperly)](https://www.nuget.org/packages/Riok.Mapperly/) ![GitHub Repo stars](https://img.shields.io/github/stars/riok/mapperly?style=social) 2023-04-16 + 7 [MagicMap](/docs/MagicMap) [![Nuget](https://img.shields.io/nuget/dt/MagicMap?label=MagicMap)](https://www.nuget.org/packages/MagicMap/) ![GitHub Repo stars](https://img.shields.io/github/stars/bramerdaniel/MagicMap?style=social) 2023-10-08 - 8 [MapTo](/docs/MapTo) [![Nuget](https://img.shields.io/nuget/dt/MapTo?label=MapTo)](https://www.nuget.org/packages/MapTo/) ![GitHub Repo stars](https://img.shields.io/github/stars/mrtaikandi/MapTo?style=social) 2023-10-05 + 8 [mapperly](/docs/mapperly) [![Nuget](https://img.shields.io/nuget/dt/Riok.Mapperly?label=Riok.Mapperly)](https://www.nuget.org/packages/Riok.Mapperly/) ![GitHub Repo stars](https://img.shields.io/github/stars/riok/mapperly?style=social) 2023-04-16 - 9 [NextGenMapper](/docs/NextGenMapper) [![Nuget](https://img.shields.io/nuget/dt/NextGenMapper?label=NextGenMapper)](https://www.nuget.org/packages/NextGenMapper/) ![GitHub Repo stars](https://img.shields.io/github/stars/DedAnton/NextGenMapper?style=social) 2023-08-16 + 9 [MapTo](/docs/MapTo) [![Nuget](https://img.shields.io/nuget/dt/MapTo?label=MapTo)](https://www.nuget.org/packages/MapTo/) ![GitHub Repo stars](https://img.shields.io/github/stars/mrtaikandi/MapTo?style=social) 2023-10-05 + + 10 [NextGenMapper](/docs/NextGenMapper) [![Nuget](https://img.shields.io/nuget/dt/NextGenMapper?label=NextGenMapper)](https://www.nuget.org/packages/NextGenMapper/) ![GitHub Repo stars](https://img.shields.io/github/stars/DedAnton/NextGenMapper?style=social) 2023-08-16 \ No newline at end of file diff --git a/v2/rscg_examples_site/docs/Categories/_PrimitiveMapper.mdx b/v2/rscg_examples_site/docs/Categories/_PrimitiveMapper.mdx index b95fe7dde..0839d498f 100644 --- a/v2/rscg_examples_site/docs/Categories/_PrimitiveMapper.mdx +++ b/v2/rscg_examples_site/docs/Categories/_PrimitiveMapper.mdx @@ -10,13 +10,15 @@ 5 [LightweightObjectMapper](/docs/LightweightObjectMapper) [![Nuget](https://img.shields.io/nuget/dt/LightweightObjectMapper?label=LightweightObjectMapper)](https://www.nuget.org/packages/LightweightObjectMapper/) ![GitHub Repo stars](https://img.shields.io/github/stars/stratosblue/LightweightObjectMapper?style=social) 2024-09-18 - 6 [MagicMap](/docs/MagicMap) [![Nuget](https://img.shields.io/nuget/dt/MagicMap?label=MagicMap)](https://www.nuget.org/packages/MagicMap/) ![GitHub Repo stars](https://img.shields.io/github/stars/bramerdaniel/MagicMap?style=social) 2023-10-08 + 6 [lomapper](/docs/lomapper) [![Nuget](https://img.shields.io/nuget/dt/lomapper?label=lomapper)](https://www.nuget.org/packages/lomapper/) ![GitHub Repo stars](https://img.shields.io/github/stars/jdtoon/lomapper?style=social) 2026-04-07 - 7 [mapperly](/docs/mapperly) [![Nuget](https://img.shields.io/nuget/dt/Riok.Mapperly?label=Riok.Mapperly)](https://www.nuget.org/packages/Riok.Mapperly/) ![GitHub Repo stars](https://img.shields.io/github/stars/riok/mapperly?style=social) 2023-04-16 + 7 [MagicMap](/docs/MagicMap) [![Nuget](https://img.shields.io/nuget/dt/MagicMap?label=MagicMap)](https://www.nuget.org/packages/MagicMap/) ![GitHub Repo stars](https://img.shields.io/github/stars/bramerdaniel/MagicMap?style=social) 2023-10-08 - 8 [MapTo](/docs/MapTo) [![Nuget](https://img.shields.io/nuget/dt/MapTo?label=MapTo)](https://www.nuget.org/packages/MapTo/) ![GitHub Repo stars](https://img.shields.io/github/stars/mrtaikandi/MapTo?style=social) 2023-10-05 + 8 [mapperly](/docs/mapperly) [![Nuget](https://img.shields.io/nuget/dt/Riok.Mapperly?label=Riok.Mapperly)](https://www.nuget.org/packages/Riok.Mapperly/) ![GitHub Repo stars](https://img.shields.io/github/stars/riok/mapperly?style=social) 2023-04-16 - 9 [NextGenMapper](/docs/NextGenMapper) [![Nuget](https://img.shields.io/nuget/dt/NextGenMapper?label=NextGenMapper)](https://www.nuget.org/packages/NextGenMapper/) ![GitHub Repo stars](https://img.shields.io/github/stars/DedAnton/NextGenMapper?style=social) 2023-08-16 + 9 [MapTo](/docs/MapTo) [![Nuget](https://img.shields.io/nuget/dt/MapTo?label=MapTo)](https://www.nuget.org/packages/MapTo/) ![GitHub Repo stars](https://img.shields.io/github/stars/mrtaikandi/MapTo?style=social) 2023-10-05 + + 10 [NextGenMapper](/docs/NextGenMapper) [![Nuget](https://img.shields.io/nuget/dt/NextGenMapper?label=NextGenMapper)](https://www.nuget.org/packages/NextGenMapper/) ![GitHub Repo stars](https://img.shields.io/github/stars/DedAnton/NextGenMapper?style=social) 2023-08-16 ### See category diff --git a/v2/rscg_examples_site/docs/RSCG-Examples/index.md b/v2/rscg_examples_site/docs/RSCG-Examples/index.md index 980afd6b1..07ebaad94 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: 264 RSCG list by category -description: 264 RSCG list by category +title: 265 RSCG list by category +description: 265 RSCG list by category slug: /rscg-examples --- @@ -1213,7 +1213,7 @@ import DocCardList from '@theme/DocCardList'; ## Mapper
- Expand Mapper =>examples:9 + Expand Mapper =>examples:10 @@ -1259,6 +1259,11 @@ import DocCardList from '@theme/DocCardList'; [Facet](/docs/Facet) + + + +[lomapper](/docs/lomapper) +
@@ -2078,6 +2083,8 @@ flowchart LR; Mapper--> Facet((Facet)) + Mapper--> lomapper((lomapper)) + MCP--> RSCG_MCP2OpenAPI((RSCG_MCP2OpenAPI)) MCP--> RSCG_MCP2File((RSCG_MCP2File)) diff --git a/v2/rscg_examples_site/docs/RSCG-Examples/lomapper.md b/v2/rscg_examples_site/docs/RSCG-Examples/lomapper.md new file mode 100644 index 000000000..50ad8e940 --- /dev/null +++ b/v2/rscg_examples_site/docs/RSCG-Examples/lomapper.md @@ -0,0 +1,1018 @@ +--- +sidebar_position: 2650 +title: 265 - lomapper +description: Generate mapping code at compile time using source generators. +slug: /lomapper +--- +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import TOCInline from '@theme/TOCInline'; +import SameCategory from '../Categories/_PrimitiveMapper.mdx'; + +# lomapper by Junaid Desai + + + + +## NuGet / site data +[![Nuget](https://img.shields.io/nuget/dt/lomapper?label=lomapper)](https://www.nuget.org/packages/lomapper/) +[![GitHub last commit](https://img.shields.io/github/last-commit/jdtoon/lomapper?label=updated)](https://github.com/jdtoon/lomapper) +![GitHub Repo stars](https://img.shields.io/github/stars/jdtoon/lomapper?style=social) + +## Details + +### Info +:::info + +Name: **lomapper** + +LoMapper - Lightweight Object Mapper using compile-time source generation. Zero runtime reflection. + +Author: Junaid Desai + +NuGet: +*https://www.nuget.org/packages/lomapper/* + + +You can find more details at https://github.com/jdtoon/lomapper + +Source: https://github.com/jdtoon/lomapper + +::: + +### Author +:::note +Junaid Desai +![Alt text](https://github.com/jdtoon.png) +::: + +## Original Readme +:::note + +### LoMapper + +**A tiny, focused object mapper** — Generate mapping code at compile time using Roslyn Source Generators. + +[![NuGet](https://img.shields.io/nuget/v/LoMapper.svg)](https://www.nuget.org/packages/LoMapper/) +[![NuGet Downloads](https://img.shields.io/nuget/dt/LoMapper.svg)](https://www.nuget.org/packages/LoMapper/) +[![Build Status](https://github.com/jdtoon/lomapper/actions/workflows/ci.yml/badge.svg)](https://github.com/jdtoon/lomapper/actions/workflows/ci.yml) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![.NET](https://img.shields.io/badge/.NET-Standard%202.0+-purple.svg)](https://dotnet.microsoft.com/) +[![GitHub Stars](https://img.shields.io/github/stars/jdtoon/lomapper?style=social)](https://github.com/jdtoon/lomapper) + +###### What is LoMapper? + +LoMapper is a small library that generates mapping code at compile time, saving you from writing repetitive property-by-property assignments by hand. + +**Benefits:** +- ✅ **Less boilerplate** — Stop writing manual property assignments +- ✅ **Compile-time safety** — Catch mapping issues during build, not at runtime +- ✅ **Zero runtime overhead** — No reflection, no scanning, just generated code +- ✅ **Debuggable** — F12 into generated code like it's your own +- ✅ **Simple** — Just add attributes to partial classes + +###### Quick Start + +######### Installation + +```bash +dotnet add package LoMapper +``` + +######### Basic Usage + +```csharp +using LoMapper; + +// 1. Define your types +public class UserEntity +{ + public int Id \{ get; set; } + public string Name \{ get; set; } + public string Email \{ get; set; } +} + +public class UserDto +{ + public int Id \{ get; set; } + public string Name \{ get; set; } + public string Email \{ get; set; } +} + +// 2. Create a mapper +[Mapper] +public partial class UserMapper +{ + public partial UserDto Map(UserEntity entity); +} + +// 3. Use it +var mapper = new UserMapper(); +var dto = mapper.Map(entity); +``` + +That's it! The `Map` method is generated at compile time with property-by-property assignment. + +###### Features + +######### Property Mapping +Properties are matched by name (case-insensitive): + +```csharp +public class Source \{ public int ID \{ get; set; \} } +public class Target \{ public int Id \{ get; set; \} } // ✅ Matched +``` + +######### Custom Property Mapping +Rename properties or apply transforms: + +```csharp +[Mapper] +public partial class UserMapper +{ + [MapProperty("FirstName", "FullName")] + [MapProperty("BirthDate", "Age", Transform = nameof(CalculateAge))] + public partial UserDto Map(UserEntity entity); + + private int CalculateAge(DateTime birthDate) + => DateTime.Today.Year - birthDate.Year; +} +``` + +######### Ignore Properties +Skip properties you don't want mapped: + +```csharp +[Mapper] +public partial class UserMapper +{ + [MapIgnore("InternalId")] + [MapIgnore("CacheKey")] + public partial UserDto Map(UserEntity entity); +} +``` + +######### Flatten Properties +Map nested object properties to flat target properties: + +```csharp +[Mapper] +public partial class UserMapper +{ + [FlattenProperty("Address.City", nameof(UserDto.AddressCity))] + [FlattenProperty("Address.ZipCode", nameof(UserDto.AddressZipCode))] + public partial UserDto Map(UserEntity entity); +} +``` + +Features: +- ✅ Deep nesting support (e.g., `Order.Customer.Address.City`) +- ✅ Null-safe navigation (`?.`) automatically generated +- ✅ Type-safe with compile-time validation +- ✅ Works with both reference and value types +- ✅ Combine with `[MapProperty]` and `[MapIgnore]` + +######### Lifecycle Hooks (BeforeMap / AfterMap) +Run code before or after mapping to validate inputs, set defaults, or audit results: + +```csharp +[Mapper] +public partial class UserMapper +{ + [BeforeMap(nameof(ValidateUser))] + [AfterMap(nameof(AuditUser))] + public partial UserDto Map(UserEntity entity); + + private void ValidateUser(UserEntity entity) + { + if (string.IsNullOrWhiteSpace(entity.Email)) throw new InvalidOperationException("Email required"); + } + + private void AuditUser(UserDto dto) => dto.Tags = dto.Tags.Append("mapped").ToArray(); +} +``` + +Hooks execute in order: `BeforeMap` runs before object creation and property assignments; `AfterMap` runs after the target is fully constructed (including constructor-based mappings). + +######### Nested Objects +For nested objects, declare explicit mapper methods: + +```csharp +[Mapper] +public partial class OrderMapper +{ + public partial OrderDto Map(OrderEntity entity); + public partial CustomerDto Map(CustomerEntity entity); // Used for nested Customer + public partial AddressDto Map(AddressEntity entity); // Used for nested Address +} +``` + +######### Collections +Full support for collections — `List`, `IEnumerable`, `Dictionary`, `HashSet`, and arrays: + +```csharp +public class Source \{ public List Items \{ get; set; \} } +public class Target \{ public List Items \{ get; set; \} } // ✅ Auto-mapped +``` + +######### Circular Reference Detection +LoMapper detects mapper graphs that contain cycles and stops the build with diagnostic `LOM010` so you can break the loop early. + +```csharp +[Mapper] +public partial class CircularMapper +{ + public partial TargetA Map(SourceA source); + public partial TargetB Map(SourceB source); +} + +public class SourceA \{ public SourceB? Child \{ get; set; \} } +public class SourceB \{ public SourceA? Parent \{ get; set; \} } + +public class TargetA \{ public TargetB? Child \{ get; set; \} } +public class TargetB \{ public TargetA? Parent \{ get; set; \} } +``` + +Mapping these types produces LOM010 describing the cycle. Break one side (e.g., ignore a property or change the DTO shape) to proceed. + +###### Compile-Time Diagnostics + +LoMapper catches mapping issues **before your code runs**: + +| Code | Severity | Description | +|------|----------|-------------| +| LOM001 | ⚠️ Warning | Target property has no matching source property | +| LOM002 | ❌ Error | Property types are incompatible | +| LOM003 | ❌ Error | Nested object requires mapper method | +| LOM004 | ❌ Error | Invalid transform method signature | +| LOM005 | ❌ Error | Source property not found | +| LOM006 | ❌ Error | Target property not found | +| LOM007 | ❌ Error | Invalid flatten property path | +| LOM008 | ❌ Error | Flatten target property not found | +| LOM009 | ❌ Error | Flatten type mismatch | +| LOM010 | ❌ Error | Circular reference detected in mapper graph | + +Example: +```csharp +public class Source \{ public int Id \{ get; set; \} } +public class Target \{ public int Id \{ get; set; \} public string Extra \{ get; set; \} } + +// ⚠️ LOM001: Target property 'Extra' has no matching source property +``` + +###### Benchmarks + +**Performance** + +LoMapper generates efficient code that performs well. Benchmark results mapping 10,000 objects: + +| Method | Mean | Memory | +|------------|------------|-----------| +| **LoMapper** | **174 μs** | 781 KB | +| Manual | 208 μs | 781 KB | + +*LoMapper matches the performance and memory characteristics of hand-written mapping code.* + +The generated code uses straightforward property assignments with no reflection or runtime overhead. For most applications, the performance is more than sufficient and comparable to writing the mappings yourself. + +
+Full Benchmark Details (Click to expand) + +Tested on Intel Core i7-10870H, .NET 8.0.23, Windows 11 using BenchmarkDotNet v0.14.0. + +**100 items:** 1.67 μs +**1,000 items:** 15.5 μs +**10,000 items:** 174 μs + +The generated code produces clean IL that the JIT compiler can optimize effectively. Zero allocations beyond the mapped objects themselves. + +[Full Results](https://github.com/jdtoon/lomapper/BenchmarkDotNet.Artifacts/results/) +
+```bash +cd benchmarks/LoMapper.Benchmarks +dotnet run -c Release +``` + +###### View Generated Code + +Enable generated file output in your `.csproj`: + +```xml + + true + +``` + +Find generated files in: `obj/GeneratedFiles/LoMapper.Generator/` + +###### Comparison + +| Feature | LoMapper | Manual Code | +|---------|:--------:|:-----------:| +| **Performance (10K items)** | **174 μs** | 208 μs | +| Memory overhead | **0%** | - | +| Compile-time generation | ✅ | N/A | +| Zero runtime reflection | ✅ | ✅ | +| Compile-time error detection | ✅ | ✅ | +| IntelliSense support | ✅ | ✅ | +| Nested object mapping | ✅ | ✅ | +| Collection mapping | ✅ | ✅ | +| Custom transforms | ✅ | ✅ | +| Flattening/unflattening | ✅ v0.3 | Manual | +| Projection (IQueryable) | 🔜 v1.0 | Manual | + +###### Why Use LoMapper? + +**vs Writing Mappings Manually:** +- Less repetitive code to write and maintain +- Compile-time validation catches errors early +- Automatic updates when models change +- Similar or better performance + +**When LoMapper Might Help:** +- You have many DTOs to map +- You want compile-time safety without runtime cost +- You prefer code generation over reflection +- You like seeing exactly what code runs (F12 into generated code) + +**Current Limitations:** +- Expression projection for IQueryable not yet supported (planned for v1.0) +- Some advanced mapping scenarios may need manual code + +LoMapper is a focused tool that does one thing well: generate simple, efficient mapping code. It's meant to complement your toolkit, not replace everything else. + +###### Requirements + +- .NET Standard 2.0+ (runs on .NET Core 3.1+, .NET 5+, .NET Framework 4.7.2+) +- C# 9.0+ (for partial methods) + +###### Contributing + +Contributions are welcome! Please read our [Contributing Guide](https://github.com/jdtoon/lomapper/CONTRIBUTING.md) first. + +###### License + +MIT License - see [LICENSE](https://github.com/jdtoon/lomapper/LICENSE) for details. + +--- + +**LoMapper** — A tiny tool to help you write less mapping code. + + +::: + +### About +:::note + +Generate mapping code at compile time using source generators. + + +::: + +## How to use + +### Example (source csproj, source files) + + + + + +This is the CSharp Project that references **lomapper** +```xml showLineNumbers {16} + + + + Exe + net10.0 + enable + enable + + + + true + $(BaseIntermediateOutputPath)\GX + + + + + + + + + + + + + +``` + + + + + + This is the use of **lomapper** in *Program.cs* + +```csharp showLineNumbers +using mapperDemo; +var p=new Person(); +p.FirstName = "Andrei"; +p.LastName = "Ignat"; +PersonDTO dto= new UserMapper().Map(p); +Console.WriteLine(dto.FullName); + +``` + + + + + This is the use of **lomapper** in *Person.cs* + +```csharp showLineNumbers + +public partial class Person +{ + public int ID \{ get; set; } + public string? FirstName \{ get; set; } + public string? LastName \{ get; set; } +} + + +``` + + + + + This is the use of **lomapper** in *PersonDTO.cs* + +```csharp showLineNumbers +using LoMapper; +using System.Xml.Serialization; + +namespace mapperDemo; +public partial struct PersonDTO +{ + public string? FirstName \{ get; set; } + public string? LastName \{ get; set; } + + public string FullName \{ + get + { + return FirstName + " " + LastName; + } + } +} + + +[Mapper] +public partial class UserMapper +{ + [MapIgnore(nameof(Person.ID))] + public partial PersonDTO Map(Person entity); +} +``` + + + + +### Generated Files + +Those are taken from $(BaseIntermediateOutputPath)\GX + + + + +```csharp showLineNumbers +// +#pragma warning disable IDE0005 +#pragma warning disable CS0105 +using LightweightObjectMapper; +using System; +using System; +using System.Linq; +using System.Runtime.CompilerServices; + +namespace mapperDemo +{ + sealed partial class Extensions + { + public static partial class Generated + { + /// + /// PostMappingDeclaration for to + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MappingMetadata(MappingMetadataType.PostMappingDeclaration, typeof(global::Person), typeof(global::mapperDemo.PersonDTO))] + public static global::mapperDemo.PersonDTO PostMapping_D275C37F33F4AFBD(global::Person source, global::mapperDemo.PersonDTO target) + { + target.ID = source.ID; + return target; + } + } + } +} +``` + + + + +```csharp showLineNumbers +#if !NO_LIGHTWEIGHT_OBJECT_MAPPER_PRE_CODES + +// + +#pragma warning disable IDE0161 // 转换为文件范围限定的 namespace + +using System; +using System.Collections.Generic; + +namespace LightweightObjectMapper +{ + /// + /// 映射配置接口 + /// + internal interface IMappingProfile \{ } + + /// + /// 映射后执行的动作 + /// + /// + /// + internal interface IPostMapping : IMappingProfile + { + /// + /// 映射后执行的动作 + /// + /// + /// + /// + TOut PostMapping(TIn source, TOut target); + } + + /// + /// 映射前准备 + /// + /// + /// + internal interface IMappingPrepare : IMappingProfile + { + /// + /// 映射前准备 + /// + /// + /// + TOut MappingPrepare(TIn source); + } + + /// + /// 接管完整的类型映射(仅非目标实例映射) + /// + /// + /// + internal interface ITypeMapping : IMappingProfile + { + /// + /// 接管完整的类型映射(仅非目标实例映射) + /// + /// + /// + TOut TypeMapping(TIn source); + } + + /// + /// 类型成员忽略映射 + /// + /// + internal interface ITypeMemberIgnoreMapping : IMappingProfile + { + /// + /// 类型成员忽略映射
+ /// 方法体内访问过的 所有成员,将在映射时被忽略 + ///
+ /// + /// + object? IgnoreMapping(T target); + } + + /// + /// 标记一个方法为集合映射方法
+ /// 集合映射方法应包含唯一泛型参数 T ,以及唯一参数 ,返回类型应该为 的派生类型 + ///
+ [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)] + internal sealed class CollectionMappingAttribute : Attribute + { + } + + /// + /// 标记类为映射配置类 + /// + [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] + internal sealed class MappingProfileAttribute : Attribute + { + /// + public MappingProfileAttribute() \{ } + } + + /// + /// 映射元数据 + /// + [AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)] + internal sealed class MappingMetadataAttribute : Attribute + { + /// + public MappingMetadataAttribute(MappingMetadataType type, params object[] data) \{ } + } + + /// + /// 映射元数据类型 + /// + internal enum MappingMetadataType + { + /// + /// 声明 MappingPrepare + /// + MappingPrepareDeclaration, + + /// + /// 声明 PostMapping + /// + PostMappingDeclaration, + + /// + /// 声明 TypeMapping + /// + TypeMappingDeclaration, + + /// + /// 声明 CollectionMapping + /// + CollectionMappingDeclaration, + + /// + /// 忽略成员声明 + /// + IgnoreMembersDeclaration, + + /// + /// 类型忽略成员声明 + /// + TypeIgnoreMembersDeclaration, + } + + /// + /// 引用其它映射配置类 + /// + [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)] + internal sealed class MappingProfileIncludeAttribute : Attribute + { + /// + public MappingProfileIncludeAttribute(params Type[] profileTypes) \{ } + } + + /// + /// 对象映射 MapTo 占位方法 + /// + [Obsolete("Do not use the placeholder extension class.", true)] + internal static class LightweightObjectMapperPlaceholderExtensions + { + private const string ErrorCallPlaceholderMethodMessage = "Do not use the placeholder extension method. If not redirect to the right mapper extension method please try fix other errors and rebuild the project."; + + /// + /// 对象映射 MapTo 占位方法
+ /// 生成 无需目标对象 的泛型映射方法,映射到 + ///
+ /// + /// + /// + [Obsolete(ErrorCallPlaceholderMethodMessage, true)] + public static TOut MapTo(this object source) + { + throw new NotImplementedException(); + } + + /// + /// 对象映射 MapTo 占位方法
+ /// 生成 需要目标对象 的泛型映射方法,映射到 + ///
+ /// + /// + /// + [Obsolete(ErrorCallPlaceholderMethodMessage, true)] + public static TOut MapTo(this object source, TOut target) + { + throw new NotImplementedException(); + } + + /// + /// 值类型 对象映射 MapTo 占位方法
+ /// 生成 需要目标值类型对象 的泛型映射方法,映射到 + ///
+ /// + /// + /// + [Obsolete(ErrorCallPlaceholderMethodMessage, true)] + public static TOut MapTo(this object source, ref TOut target) + where TOut : struct + { + throw new NotImplementedException(); + } + } +} + +#endif + +``` +
+ + + +```csharp showLineNumbers +#if !NO_LIGHTWEIGHT_OBJECT_MAPPER_PRE_CODES + +// + +#pragma warning disable IDE0161 // 转换为文件范围限定的 namespace + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; + +namespace LightweightObjectMapper +{ + /// + /// 预定义的类型映射 + /// + [MappingProfile] + internal sealed partial class PredefinedSpecialTypeMapping + : ITypeMapping + , ITypeMapping + , ITypeMapping + { + public bool TypeMapping(int source) + { + return source != 0; + } + + public bool TypeMapping(short source) + { + return source != 0; + } + + bool ITypeMapping.TypeMapping(long source) + { + return source != 0; + } + + [CollectionMapping] + public static IEnumerable? ToIEnumerable(IEnumerable? items) + { + return items?.ToList(); + } + + [CollectionMapping] + public static ICollection? ToICollection(IEnumerable? items) + { + return items?.ToList(); + } + + [CollectionMapping] + public static IReadOnlyCollection? ToIReadOnlyCollection(IEnumerable? items) + { + return items?.ToList(); + } + + [CollectionMapping] + public static IList? ToIList(IEnumerable? items) + { + return items?.ToList(); + } + + [CollectionMapping] + public static IReadOnlyList? ToIReadOnlyList(IEnumerable? items) + { + return items?.ToList(); + } + + [CollectionMapping] + public static List? ToList(IEnumerable? items) + { + return items?.ToList(); + } + } +} + +#endif + +``` + + + + +```csharp showLineNumbers +// +#pragma warning disable IDE0005 +#pragma warning disable CS0105 +using System; +using System.Linq; +using System.Runtime.CompilerServices; + +namespace LightweightObjectMapper +{ + internal static partial class LOMMapExtensions_mapperDemo + { + /// + /// Map to the following types:
+ ///
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TOut MapTo(this global::Person source) + { + if (source == null) + { + throw new ArgumentNullException(nameof(source)); + } + + if (typeof(TOut) == typeof(global::mapperDemo.PersonDTO)) + { + var target = new global::mapperDemo.PersonDTO() + { + LastName = source.LastName, + FirstName = source.FirstName, + ID = source.ID, + }; + target = global::mapperDemo.Extensions.Generated.PostMapping_D275C37F33F4AFBD(source, target); + return (TOut)(target as object); + } + + throw new global::System.NotImplementedException($"No mapping code for {typeof(TOut)}."); + } + } +} +``` +
+ + + +```csharp showLineNumbers +// +#pragma warning disable IDE0005 +#pragma warning disable CS0105 +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System; +using System.Linq; +using System.Runtime.CompilerServices; + +namespace LightweightObjectMapper +{ + sealed partial class PredefinedSpecialTypeMapping + { + public static partial class Generated + { + /// + /// TypeMappingDeclaration for to + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MappingMetadata(MappingMetadataType.TypeMappingDeclaration, typeof(int), typeof(bool))] + public static bool TypeMapping_A07AFC9A322FFA04(int source) + { + return source != 0; + } + + /// + /// TypeMappingDeclaration for to + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MappingMetadata(MappingMetadataType.TypeMappingDeclaration, typeof(short), typeof(bool))] + public static bool TypeMapping_946949E7222BC174(short source) + { + return source != 0; + } + + /// + /// TypeMappingDeclaration for to + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MappingMetadata(MappingMetadataType.TypeMappingDeclaration, typeof(long), typeof(bool))] + public static bool TypeMapping_3C4D395B4EF43E87(long source) + { + return source != 0; + } + + /// + /// CollectionMappingDeclaration for + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MappingMetadata(MappingMetadataType.CollectionMappingDeclaration, typeof(global::System.Collections.Generic.IEnumerable<>))] + public static global::System.Collections.Generic.IEnumerable CollectionMapping_CEFAD35E246FD0F7(global::System.Collections.Generic.IEnumerable items) + { + return items?.ToList(); + } + + /// + /// CollectionMappingDeclaration for + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MappingMetadata(MappingMetadataType.CollectionMappingDeclaration, typeof(global::System.Collections.Generic.ICollection<>))] + public static global::System.Collections.Generic.ICollection CollectionMapping_37FFD1A2226B51E9(global::System.Collections.Generic.IEnumerable items) + { + return items?.ToList(); + } + + /// + /// CollectionMappingDeclaration for + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MappingMetadata(MappingMetadataType.CollectionMappingDeclaration, typeof(global::System.Collections.Generic.IReadOnlyCollection<>))] + public static global::System.Collections.Generic.IReadOnlyCollection CollectionMapping_AF82A9960EE0C495(global::System.Collections.Generic.IEnumerable items) + { + return items?.ToList(); + } + + /// + /// CollectionMappingDeclaration for + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MappingMetadata(MappingMetadataType.CollectionMappingDeclaration, typeof(global::System.Collections.Generic.IList<>))] + public static global::System.Collections.Generic.IList CollectionMapping_284BCB723CA17B0E(global::System.Collections.Generic.IEnumerable items) + { + return items?.ToList(); + } + + /// + /// CollectionMappingDeclaration for + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MappingMetadata(MappingMetadataType.CollectionMappingDeclaration, typeof(global::System.Collections.Generic.IReadOnlyList<>))] + public static global::System.Collections.Generic.IReadOnlyList CollectionMapping_976EA1DB5B772C59(global::System.Collections.Generic.IEnumerable items) + { + return items?.ToList(); + } + + /// + /// CollectionMappingDeclaration for + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MappingMetadata(MappingMetadataType.CollectionMappingDeclaration, typeof(global::System.Collections.Generic.List<>))] + public static global::System.Collections.Generic.List CollectionMapping_070F0D0F908DAF14(global::System.Collections.Generic.IEnumerable items) + { + return items?.ToList(); + } + } + } +} +``` + + + + +```csharp showLineNumbers +// +#nullable enable + +namespace mapperDemo +{ + public partial class UserMapper + { + public partial mapperDemo.PersonDTO Map(Person entity) + { + return new mapperDemo.PersonDTO + { + FirstName = entity.FirstName, + LastName = entity.LastName + }; + } + } +} + +``` + + + +
+## Useful + +### Download Example (.NET C#) + +:::tip + +[Download Example project lomapper ](/sources/lomapper.zip) + +::: + + +### Share lomapper + + + +https://ignatandrei.github.io/RSCG_Examples/v2/docs/lomapper + + + diff --git a/v2/rscg_examples_site/docs/about.md b/v2/rscg_examples_site/docs/about.md index 8b154ad68..e4f2b5edf 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 264 Roslyn Source Code Generator (RSCG) +of 265 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 25ac3b9e9..b48ea8bb3 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'; -## 264 RSCG with examples in descending chronological order +## 265 RSCG with examples in descending chronological order -This is the list of 264 ( 16 from Microsoft) RSCG with examples +This is the list of 265 ( 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 264 ( 16 from Microsoft) RSCG with examples | No | Name | Date | Category | | --------- | ----- | ---- | -------- | +|265| [lomapper by Junaid Desai ](/docs/lomapper)|2026-04-07 => 07 April 2026 | [Mapper](/docs/Categories/Mapper) | |264| [Najlot.Audit.SourceGenerator by Najlot ](/docs/Najlot.Audit.SourceGenerator)|2026-04-06 => 06 April 2026 | [Audit](/docs/Categories/Audit) | |263| [TaggedEnum by Alor'idal ](/docs/TaggedEnum)|2026-04-05 => 05 April 2026 | [Enum](/docs/Categories/Enum) | |262| [SvgIconGenerator by Matt Schneeberger ](/docs/SvgIconGenerator)|2026-04-04 => 04 April 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 666f25220..575a489d1 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: '264 Examples (16 from MSFT)', +title: '265 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 387e371d5..3ba7f6bd3 100644 --- a/v2/rscg_examples_site/static/exports/RSCG.json +++ b/v2/rscg_examples_site/static/exports/RSCG.json @@ -2113,6 +2113,14 @@ "Source": "https://github.com/najlot/Audit", "Category": "Audit", "AddedOn": "2026-04-06T00:00:00" + }, + { + "Name": "lomapper", + "Link": "https://ignatandrei.github.io/RSCG_Examples/v2/docs/loMapper", + "NuGet": "https://www.nuget.org/packages/lomapper/", + "Source": "https://github.com/jdtoon/lomapper", + "Category": "Mapper", + "AddedOn": "2026-04-07T00: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 7a543c5d4..5e440e695 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/lomapper.zip b/v2/rscg_examples_site/static/sources/lomapper.zip new file mode 100644 index 000000000..e8194a686 Binary files /dev/null and b/v2/rscg_examples_site/static/sources/lomapper.zip differ