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
Leave a Reply