RSCG – Curry – Partial function – part 12
name | PartiallyApplied |
nuget |
https://www.nuget.org/packages/PartiallyApplied/ |
link | https://github.com/JasonBock/PartiallyApplied |
author | Andrei Ignat |
This will generate curry for your functions
The code that you start with is
public class Accounting { public static float Discount( float discount, float price) { var val= price * (1- discount); return val; } }
The code that you will use is
var disc10Percent = Partially.Apply(Accounting.Discount, 1/10f); Console.WriteLine(disc10Percent(disc10Percent(100)));
The code that is generated is
public static partial class Partially { public static Func<float, float> Apply(Func<float, float, float> method, float discount) => new((price) => method(discount, price)); }
Example Code: https://github.com/ignatandrei/RSCG_Examples/tree/main/PartiallyFunction
All RSCG
Roslyn Source Code GeneratorsRSCG- Method Decorator – part 11
name | Method decorator |
nuget |
https://www.nuget.org/packages/AOPMethodsCommon/ |
link | http://msprogrammer.serviciipeweb.ro/category/roslyn/ |
author | Andrei Ignat |
This will generate code to decorate methods with anything you want ( stopwatch, logging , authorization…)
The code that you start with is
[AutoMethods(template =TemplateMethod.CustomTemplateFile,MethodPrefix ="prv" ,CustomTemplateFileName ="MethodDecorator.txt")] public partial class Person { public string FirstName{ get; set; } public string LastName { get; set; } private string prvFullName() { return FirstName + " " + LastName; } }
The code that you will use is
var p = new Person(); p.FirstName = "Andrei"; p.LastName = "Ignat"; Console.WriteLine(p.FullName());
The code that is generated is
[GeneratedCode("AOPMethods", "2021.2.22.1125")] [CompilerGenerated] public partial class Person{ public string FullName ( [CallerMemberName] string memberName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0){ var sw=Stopwatch.StartNew(); try{ Console.WriteLine("--prvFullName start "); Console.WriteLine("called from class :"+memberName ); Console.WriteLine("called from file :"+sourceFilePath ); Console.WriteLine("called from line :"+sourceLineNumber ); prvFullName(); } catch(Exception ex){ Console.WriteLine("error in prvFullName:" + ex.Message); throw; } finally{ Console.WriteLine($"--------prvFullName end in {sw.Elapsed.TotalMilliseconds}"); } }//end FullName }
Example Code: https://github.com/ignatandrei/RSCG_Examples/tree/main/MethodDecorator
All RSCG
Roslyn Source Code GeneratorsRSGC- Dynamic Mock – part 10
name | MockSourceGenerator |
nuget |
https://www.nuget.org/packages/MockSourceGenerator/ |
link | https://github.com/hermanussen/MockSourceGenerator/ |
author | Robin Hermanussen |
This will generate Mock classes directly for any interface – with your implementation.
The code that you start with is
public interface IMatOps { public int Add(int a, int b); public int Division(int a, int b); }
The code that you will use is
var mock = (IMatOps)new MatOpsMock { MockAdd = (a, b) => a+b, MockDivision = (a,b)=> a/b };
The code that is generated is
public partial class MatOpsMock : global::MatOps.IMatOps { /// <summary> /// Set this to true, if you want members that don't have a mock implementation /// to return a default value instead of throwing an exception. /// </summary> public bool ReturnDefaultIfNotMocked { get; set; } private System.Collections.Generic.List<HistoryEntry> historyEntries = new System.Collections.Generic.List<HistoryEntry>(); public System.Collections.ObjectModel.ReadOnlyCollection<HistoryEntry> HistoryEntries { get { return historyEntries.AsReadOnly(); } } /// <summary> /// Implemented for type global::MatOps.IMatOps (Public, same assembly: False) /// </summary> public Func<int,int,int>? MockAdd { get; set; } public int Add(int a, int b) { historyEntries.Add(new HistoryEntry("Add", new [] { $"{a}", $"{b}" })); if (MockAdd == null) { if (ReturnDefaultIfNotMocked) { return default(int); } else { throw new NotImplementedException("Method 'MockAdd' was called, but no mock implementation was provided"); } } return MockAdd(a, b); } /// <summary> /// Implemented for type global::MatOps.IMatOps (Public, same assembly: False) /// </summary> public Func<int,int,int>? MockDivision { get; set; } public int Division(int a, int b) { historyEntries.Add(new HistoryEntry("Division", new [] { $"{a}", $"{b}" })); if (MockDivision == null) { if (ReturnDefaultIfNotMocked) { return default(int); } else { throw new NotImplementedException("Method 'MockDivision' was called, but no mock implementation was provided"); } } return MockDivision(a, b); } }
Example Code: https://github.com/ignatandrei/RSCG_Examples/tree/main/DynamicMocking
All RSCG
Roslyn Source Code GeneratorsRSGC- MetadataFromObject – part 9
name | Metadata from object |
nuget |
https://www.nuget.org/packages/AOPMethodsCommon/ |
link | http://msprogrammer.serviciipeweb.ro/category/roslyn/ |
author | Andrei Ignat |
This will generate code to retrieve the values of properties directly, not by reflection
The code that you start with is
[AutoMethods(template = TemplateMethod.CustomTemplateFile, CustomTemplateFileName = "GenerateFromPOCO.txt")] public partial class Person { public string FirstName { get; set; } public string LastName { get; set; } }
The code that you will use is
var p = new Person(); p.FirstName = "Andrei"; p.LastName = "Ignat"; var last = p.ValueProperty(Person_EnumProps.LastName); var first = p.ValueProperty("FirstName"); Console.WriteLine(last + " "+first);
The code that is generated is
public enum Person_EnumProps{ None ,FirstName // Public ,LastName // Public } partial class Person{ public object ValueProperty(Person_EnumProps val){ if(val == Person_EnumProps.FirstName) { return this.FirstName; } if(val == Person_EnumProps.LastName) { return this.LastName; } throw new ArgumentException("cannot find "+ val); } public object ValueProperty(string val){ if(string.Compare("FirstName",val,StringComparison.CurrentCultureIgnoreCase)==0) { return this.FirstName; } if(string.Compare("LastName",val,StringComparison.CurrentCultureIgnoreCase)==0) { return this.LastName; } throw new ArgumentException("cannot find "+ val); } }
Example Code: https://github.com/ignatandrei/RSCG_Examples/tree/main/MetadataFromObject
All RSCG
Roslyn Source Code GeneratorsFriday Links 412
RSGC-Builder Design Pattern – part 8
name | data-builder-generator |
nuget |
https://www.nuget.org/packages/DasMulli.DataBuilderGenerator/ |
link | https://github.com/dasMulli/data-builder-generator |
author | Martin Andreas Ulrich |
Implements the Builder Design pattern for any class. Useful , at least, for test projects
The code that you start with is
[GenerateDataBuilder] public class Person { public string FirstName { get; set; } public string? MiddleNames { get; set; } public string LastName { get; set; } }
The code that you will use is
var pOld = new Person(); pOld.FirstName = "Andrei"; pOld.LastName = "Ignat"; pOld.MiddleNames = "G"; var build = new PersonBuilder(pOld).WithoutMiddleNames().WithFirstName("Florin"); var pNew = build.Build(); Console.WriteLine(pNew.FirstName);
The code that is generated is
public partial class PersonBuilder { private string? _firstName; private string? _middleNames; private string? _lastName; public PersonBuilder() { } public PersonBuilder(PersonBuilder otherBuilder) { _firstName = otherBuilder._firstName; _middleNames = otherBuilder._middleNames; _lastName = otherBuilder._lastName; } public PersonBuilder(Person existingInstance) { _firstName = existingInstance.FirstName; _middleNames = existingInstance.MiddleNames; _lastName = existingInstance.LastName; } public PersonBuilder WithFirstName(string firstName) { var mutatedBuilder = new PersonBuilder(this); mutatedBuilder._firstName = firstName; return mutatedBuilder; } public PersonBuilder WithMiddleNames(string? middleNames) { var mutatedBuilder = new PersonBuilder(this); mutatedBuilder._middleNames = middleNames; return mutatedBuilder; } public PersonBuilder WithoutMiddleNames() { var mutatedBuilder = new PersonBuilder(this); mutatedBuilder._middleNames = null; return mutatedBuilder; } public PersonBuilder WithLastName(string lastName) { var mutatedBuilder = new PersonBuilder(this); mutatedBuilder._lastName = lastName; return mutatedBuilder; } public Person Build() { var instance = new Person(); if (!(_firstName is null)) instance.FirstName = _firstName; if (!(_middleNames is null)) instance.MiddleNames = _middleNames; if (!(_lastName is null)) instance.LastName = _lastName; return instance; } }
Example Code: https://github.com/ignatandrei/RSCG_Examples/tree/main/DP_Builder
All RSCG
Roslyn Source Code GeneratorsRSGC – Skinny Controllers- part 7
name | Skinny Controllers |
nuget |
https://www.nuget.org/packages/SkinnyControllersCommon/ |
link | http://msprogrammer.serviciipeweb.ro/category/roslyn/ |
author | Andrei Ignat |
This will generate code for WebAPI for each method of a field in the controller
The code that you start with is
public class PersonRepository { public async Task<Person> Get(int id) { await Task.Delay(1000); return new Person() { ID = id, Name = "Andrei " + id }; } //add more functions here to make the demo }
The code that you will use is
[AutoActions(template = TemplateIndicator.AllPostWithRecord, FieldsName = new[] { "*" }, ExcludeFields = new[] { "_logger" })] [ApiController] [Route("[controller]/[action]")] public partial class PersonController : ControllerBase { private readonly PersonRepository pr; private readonly ILogger<PersonController> _logger; public PersonController(PersonRepository pr, ILogger<PersonController> logger) { this.pr = pr; _logger = logger; } }
The code that is generated is
[HttpPost] public System.Threading.Tasks.Task<AOPSkinnyController.Classes.Person> Get( recGet_143266108 data ){ return pr.Get(data.id); }
Example Code: https://github.com/ignatandrei/RSCG_Examples/tree/main/SkinnyControllers
All RSCG
Roslyn Source Code GeneratorsRSGC – DTO Mapper – part 6
name | GeneratedMapper |
nuget |
https://www.nuget.org/packages/GeneratedMapper/ |
link | https://github.com/ThomasBleijendaal/GeneratedMapper |
author | Thomas Bleijendaal |
AutoMapping from a POCO to a DTO. Lots of customizations
The code that you start with is
public class Department { public int ID { get; set; } public string Name { get; set; } public List<string> Employees { get; set; } } [IgnoreInTarget("Employees")] [MapFrom(typeof(Department))] public class DepartmentDTO { public int ID { get; set; } public string Name{get; set;} [MapWith("Employees",typeof(ResolverLength))] public int EmployeesNr { get; set; } } public class ResolverLength { public int Resolve(List<string> input) { return ((input?.Count) ?? 0); } }
The code that you will use is
static void Main(string[] args) { var dep = new Department(); dep.Name = "IT"; dep.ID = 1; dep.Employees = new List<string>(); dep.Employees.Add("Andrei"); var dto = dep.MapToDepartmentDTO(); Console.WriteLine(dto.Name+"=>"+ dto.EmployeesNr); }
The code that is generated is
namespace DTOMapper { public static partial class DepartmentMapToExtensions { public static DTOMapper.DepartmentDTO MapToDepartmentDTO(this DTOMapper.Department self) { if (self is null) { throw new ArgumentNullException(nameof(self), "DTOMapper.Department -> DTOMapper.DepartmentDTO: Source is null."); } var resolverLength = new DTOMapper.ResolverLength(); var target = new DTOMapper.DepartmentDTO { ID = self.ID, Name = (self.Name ?? throw new GeneratedMapper.Exceptions.PropertyNullException("DTOMapper.Department -> DTOMapper.DepartmentDTO: Property Name is null.")), EmployeesNr = resolverLength.Resolve((self.Employees ?? throw new GeneratedMapper.Exceptions.PropertyNullException("DTOMapper.Department -> DTOMapper.DepartmentDTO: Property Employees is null."))), }; return target; } } }
Example Code: https://github.com/ignatandrei/RSCG_Examples/tree/main/DTOMapper
All RSCG
Roslyn Source Code GeneratorsRSGC-Constructor – Deconstructor – part 5
name | CopyConstructor + Deconstructor |
nuget |
https://www.nuget.org/packages/AOPMethodsCommon/ |
link | http://msprogrammer.serviciipeweb.ro/category/roslyn/ |
author | Andrei Ignat |
This will generate code for a POCO to generate copy constructor and deconstructor
The code that you start with is
[AutoMethods(template = TemplateMethod.CustomTemplateFile, CustomTemplateFileName = "CopyConstructorDestructor.txt")] partial class Person { public string FirstName { get; set; } public string LastName { get; set; } }
The code that you will use is
var pOldPerson = new Person(); pOldPerson.FirstName = "Andrei"; pOldPerson.LastName = "Ignat"; var newPerson = new Person(pOldPerson); Console.WriteLine(newPerson.FirstName); var (_, last) = newPerson; Console.WriteLine(last);
The code that is generated is
public Person (){ OnConstructor(); } public Person(IPerson other):base(){ BeforeCopyConstructor(other); CopyPropertiesFrom(other); AfterCopyConstructor(other); } public void CopyPropertiesFrom(IPerson other){ this.FirstName = other.FirstName; this.LastName = other.LastName; } public void Deconstruct( out string FirstName, out string LastName) { FirstName = this.FirstName; LastName = this.LastName; }
Example Code: https://github.com/ignatandrei/RSCG_Examples/tree/main/CopyConstructor