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