Farskeptic.AutoCompose by farskeptic/jmagel
Nuget / site data
Details
Info
Name: Farskeptic.AutoCompose
A .NET source generator that enables composition without having to implement pass-thru code. No runtime reflection.
Author: farskeptic/jmagel
NuGet: https://www.nuget.org/packages/Farskeptic.AutoCompose/
You can find more details at https://github.com/farskeptic/AutoCompose
Original Readme
AutoCompose
AutoCompose is a .NET source generator that allows the implementation of an interface via composition without having to implement pass-thru code. There is no runtime reflection.
- All unimplemented properties and methods on the interface are automatically generated as pass-thru logic.
- Any implemented properties or methods will NOT be generated by AutoCompose.
- As you add or remove implementations, AutoCompose re-generates to compensate.
This allows object composition to be used as easily as inheritance.
Getting Started
Given an interface named ISample:
Create a class implementing ISample via composition using AutoCompose by:
- Implementing a partial class
- Adding the instance of the interface as a member variable (e.g. _sample)
- Injecting the variable in the constructor
- Decorating the class with the AutoCompose attribute
[AutoCompose(typeof(ISample), "_sample")]
public partial class Sample: ISample
{
protected ISample _sample;
// all non-implemented properties and methods are automatically generated as pass-thru logic
public Sample(ISample sample)
{
_sample = sample;
}
:
}
AutoCompose runs at compile time, and generates the source required to fully implement the interface.
Composition as easily as Inheritance
When trying to decide between inheritance or composition, the amount of pass-thru code that must be coded and maintained often plays a role in the decision.
Example: When we need to override the implementation of a single method for an interface that contains 10 methods, the code burden of implementing and maintaing the 9 pass-thru methods often causes developers to choose inheritance over composition, regardless of other considerations.
With AutoCompose, this issue goes away. The developer is free to choose inheritance or composition for purely architectural reasons, without having to worry about implementation or maintenance difficulties.
When should I use AutoCompose?
Any time you want to use composition, and have at least one property or method that would be implemented as pass-thru code, AutoCompose can take that burden away from you.
Known Limitations
- AutoCompose currently works for interfaces only. It DOES NOT work (yet) for abstract classes.
- AutoCompose may not work if your code has multiple definitions of an interface with the same name. AutoCompose (currently) just picks the first matching symbol, and so does not discriminate the target-interface based purely on namespaces.
- If your code contains extremely deep namespaces and would generate source code files with very long names, then there can be filename-length conflicts with the windows file system.
About
Generating decorators for classes that implements interfaces.
How to use
Example ( source csproj, source files )
- CSharp Project
- Program.cs
- Coffee.cs
- ICoffee.cs
- CoffeeWithLogging.cs
This is the CSharp Project that references Farskeptic.AutoCompose
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Farskeptic.AutoCompose" Version="1.0.1" />
</ItemGroup>
<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
</Project>
This is the use of Farskeptic.AutoCompose in Program.cs
using Decorator;
ICoffee c = new Coffee();
c = new CoffeeWithLogging(c);
await c.Prepare();
var ingredients = c.GetIngredients();
This is the use of Farskeptic.AutoCompose in Coffee.cs
namespace Decorator;
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" };
}
This is the use of Farskeptic.AutoCompose in ICoffee.cs
namespace Decorator;
internal interface ICoffee
{
Task<bool> Prepare();
string[] GetIngredients();
}
This is the use of Farskeptic.AutoCompose in CoffeeWithLogging.cs
using AutoCompose.Generator.Attributes;
namespace Decorator;
[AutoCompose(typeof(ICoffee), nameof(_cof))]
internal partial class CoffeeWithLogging : ICoffee
{
protected ICoffee _cof;
public CoffeeWithLogging(ICoffee cof)
{
this._cof = cof;
}
public string[] GetIngredients()
{
Console.WriteLine("CoffeeWithLogging.GetIngredients");
return this._cof.GetIngredients();
}
}
Generated Files
Those are taken from $(BaseIntermediateOutputPath)\GX
- Decorator.CoffeeWithLogging.g.cs
// <auto-generated>
// WARNING: THIS CODE IS AUTO-GENERATED AT COMPILE-TIME. ANY CHANGES WILL BE OVERWRITTEN ON NEXT COMPILE.
// </auto-generated>
namespace Decorator
{
internal partial class CoffeeWithLogging
{
public virtual Task<bool> Prepare()
{
return _cof.Prepare();
}
}
}
Usefull
Download Example (.NET C# )
Share Farskeptic.AutoCompose
https://ignatandrei.github.io/RSCG_Examples/v2/docs/Farskeptic.AutoCompose