NameHillSoftware.TypeAdoption 1.0.2

dotnet add package NameHillSoftware.TypeAdoption --version 1.0.2
                    
NuGet\Install-Package NameHillSoftware.TypeAdoption -Version 1.0.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="NameHillSoftware.TypeAdoption" Version="1.0.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="NameHillSoftware.TypeAdoption" Version="1.0.2" />
                    
Directory.Packages.props
<PackageReference Include="NameHillSoftware.TypeAdoption" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add NameHillSoftware.TypeAdoption --version 1.0.2
                    
#r "nuget: NameHillSoftware.TypeAdoption, 1.0.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package NameHillSoftware.TypeAdoption@1.0.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=NameHillSoftware.TypeAdoption&version=1.0.2
                    
Install as a Cake Addin
#tool nuget:?package=NameHillSoftware.TypeAdoption&version=1.0.2
                    
Install as a Cake Tool

TypeAdoption

Adopt the implementations of members in your class and embrace delegation, composition over inheritance, and mix-in style coding in C#.

Usage

When the [Adopt] attribute is attached to a member, the parent class will automatically adopt the interface that the member is declared as. All interface members will delegate to the adopted member, unless specified in the working class. For example:

public partial class ConfiguredLogger<T>(ILogger<T> innerLogger)
{
    [Adopt]
    private readonly ILogger<T> _innerLogger = innerLogger;

    public bool IsEnabled(LogLevel logLevel)
    {
        return logLevel > LogLevel.Debug;
    }

    // Other ILogger members are automatically delegated to _innerLogger.
}

And what is automatically generated:

// <auto-generated/>
#nullable restore
namespace TypeAdoption.Sample;

public partial class ConfiguredLogger<T> : Microsoft.Extensions.Logging.ILogger<T>
{
    #nullable enable
    public System.IDisposable? BeginScope<TState>(TState state) where TState : notnull
    {
        return _innerLogger.BeginScope<TState>(state);
    }
    #nullable restore

    #nullable enable
    public void Log<TState>(Microsoft.Extensions.Logging.LogLevel logLevel, Microsoft.Extensions.Logging.EventId eventId, TState state, System.Exception? exception, System.Func<TState, System.Exception?, string> formatter)
    {
        _innerLogger.Log<TState>(logLevel, eventId, state, exception, formatter);
    }
    #nullable restore
}

Advanced Usage

You can keep the adoption secret by setting the Publicly option to false, generating an explicit implementation:

public interface ILoggerConfiguration
{
    string? LogTag { get; set; }
    int MinLevel { get; set; }
    LogLevel GetMinLevel();
}

public class Configuration : ILoggerConfiguration
{
    public string? LogTag { get; set; }

    public int MinLevel { get; set; }

    public LogLevel GetMinLevel()
    {
        return (LogLevel)MinLevel;
    }
}

public partial class ConfiguredLogger<T>(ILogger<T> innerLogger, IConfiguration configuration)
{
    [Adopt]
    private readonly ILogger<T> _innerLogger = innerLogger;

    [Adopt(Publicly = false)]
    private readonly IConfiguration _innerConfiguration = configuration;

    public bool IsEnabled(LogLevel logLevel)
    {
        return logLevel >= _innerConfiguration.GetMinLevel();
    }

    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
    {
        if (IsEnabled(logLevel))
            _innerLogger.Log(logLevel, eventId, state, exception, formatter);
    }
}

The automatically generated class will look like this:

// <auto-generated/>
#nullable restore
namespace TypeAdoption.Tests.Lib;

public partial class ConfiguredLogger<T> : TypeAdoption.Tests.Lib.ILoggerConfiguration
{
    Microsoft.Extensions.Logging.LogLevel TypeAdoption.Tests.Lib.ILoggerConfiguration.GetMinLevel()
    {
        return _hiddenConfiguration.GetMinLevel();
    }

    #nullable enable
    string? TypeAdoption.Tests.Lib.ILoggerConfiguration.LogTag { get => _hiddenConfiguration.LogTag; set => _hiddenConfiguration.LogTag = value; }
    #nullable restore

    int TypeAdoption.Tests.Lib.ILoggerConfiguration.MinLevel { get => _hiddenConfiguration.MinLevel; set => _hiddenConfiguration.MinLevel = value; }
}

The auto-generated logger adoption is reduced to just one method:

// <auto-generated/>
#nullable restore
namespace TypeAdoption.Sample;

public partial class ConfiguredLogger<T> : Microsoft.Extensions.Logging.ILogger<T>
{
    #nullable enable
    public System.IDisposable? BeginScope<TState>(TState state) where TState : notnull
    {
        return _innerLogger.BeginScope<TState>(state);
    }
    #nullable restore
}

And calling the code:

var entity = new AdoptingEntity(new HumanEntity());
using var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
var logger = new ConfiguredLogger<Program>(loggerFactory.CreateLogger<Program>(), new Configuration
{
    MinLevel = LogLevel.Information,
});

// Will log
logger.LogInformation(entity.SayHello());

((ILoggerConfiguration)logger).MinLevel = LogLevel.Warning;

// Won't log
logger.LogInformation(entity.Backpack.ToString());

Notes

Normal compiler rules apply — so any conflicts, such as two interfaces with equivalent signatures, will have to be resolved in the actual class.

Development

Credit

This project was originally started as a fork of Decorator Generator. All credit to Leopoldo Fu for their well-written library, it provided an excellent base for getting started!

License

This project is licensed under the Apache License Version 2.0 - see the LICENSE file for details.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.2 26 1/21/2026
1.0.1 34 1/20/2026
1.0.0 31 1/20/2026
0.2.0 31 1/20/2026

1.0.2

           - More documentation improvements

           1.0.1

           - Improved documentation

           1.0.0

           - Added project documentation and licensing.

           0.2.0

           - Support attaching [Adopt] to properties.
           - Support events.
           - Support nested interfaces.

           0.1.0

           - Initial version supporting attaching [Adopt] to members.