RSCG – CopyCat
RSCG – CopyCat
name | CopyCat |
nuget | https://www.nuget.org/packages/Copycat/ |
link | https://github.com/Otaman/Copycat/ |
author | Serhii Buta |
Implementation of the Decorator pattern in C# – only for not implemented methods
This is how you can use CopyCat .
The code that you start with is
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net8.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> <ItemGroup> <PackageReference Include="Copycat" Version="0.2.0-beta.1" OutputItemType="Analyzer" /> </ItemGroup> <PropertyGroup> <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> <CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath> </PropertyGroup> </Project>
The code that you will use is
using CCDemo; ICoffee c =new Coffee(); c= new CoffeeWithLogging(c); await c.Prepare();
namespace CCDemo; internal interface ICoffee { //for the moment does not work for properties in interface //string? Name { get; set; } Task<bool> Prepare(); string[] GetIngredients(); }
namespace CCDemo; internal class Coffee : ICoffee { public string? Name { get; set; } public async Task<bool> Prepare() { Console.WriteLine("start prepare coffee"); await Task.Delay(1000); Console.WriteLine("finish prepare coffee"); return true; } public string[] GetIngredients() => new[] { "water", "coffee" }; }
using Copycat; namespace CCDemo; [Decorate] internal partial class CoffeeWithLogging: ICoffee { [Template] private string[] AddLogging(Func<string[]> action) { try { Console.WriteLine($"start logging {nameof(action)} "); return action(); } catch (Exception e) { Console.WriteLine($"exception {nameof(action)} "); throw; } finally { Console.WriteLine($"end logging {nameof(action)} "); } } [Template] public async Task<bool> AddLogging(Func<Task<bool>> action) { try { Console.WriteLine($"start logging {nameof(action)} "); return await action(); } catch (Exception e) { Console.WriteLine($"exception {nameof(action)} "); throw; } finally { Console.WriteLine($"end logging {nameof(action)} "); } } }
The code that is generated is
// <auto-generated/> using Copycat; namespace CCDemo; internal partial class CoffeeWithLogging { private CCDemo.ICoffee _decorated; public CoffeeWithLogging(CCDemo.ICoffee decorated) { _decorated = decorated; } /// <see cref = "CoffeeWithLogging.AddLogging(Func{Task{bool}})"/> public async //for the moment does not work for properties in interface //string? Name { get; set; } Task<bool> Prepare() { try { Console.WriteLine($"start logging {nameof(Prepare)} "); return await _decorated.Prepare(); } catch (Exception e) { Console.WriteLine($"exception {nameof(Prepare)} "); throw; } finally { Console.WriteLine($"end logging {nameof(Prepare)} "); } } /// <see cref = "CoffeeWithLogging.AddLogging(Func{string[]})"/> public string[] GetIngredients() { try { Console.WriteLine($"start logging {nameof(GetIngredients)} "); return _decorated.GetIngredients(); } catch (Exception e) { Console.WriteLine($"exception {nameof(GetIngredients)} "); throw; } finally { Console.WriteLine($"end logging {nameof(GetIngredients)} "); } } }
Code and pdf at
https://ignatandrei.github.io/RSCG_Examples/v2/docs/CopyCat