NameHillSoftware.TypeAdoption
0.2.0
See the version list below for details.
dotnet add package NameHillSoftware.TypeAdoption --version 0.2.0
NuGet\Install-Package NameHillSoftware.TypeAdoption -Version 0.2.0
<PackageReference Include="NameHillSoftware.TypeAdoption" Version="0.2.0" />
<PackageVersion Include="NameHillSoftware.TypeAdoption" Version="0.2.0" />
<PackageReference Include="NameHillSoftware.TypeAdoption" />
paket add NameHillSoftware.TypeAdoption --version 0.2.0
#r "nuget: NameHillSoftware.TypeAdoption, 0.2.0"
#:package NameHillSoftware.TypeAdoption@0.2.0
#addin nuget:?package=NameHillSoftware.TypeAdoption&version=0.2.0
#tool nuget:?package=NameHillSoftware.TypeAdoption&version=0.2.0
TypeAdoption
<img src="./TypeAdoption/project-icon.svg" width="300px" alt="TypeAdoption Logo"/>
Adopt the implementations of members in your class and embrace delegation, composition over inheritance, and mix-in style coding in C#.
Installation
Add it to your csproj:
<PackageReference Include="NameHillSoftware.TypeAdoption" Version="0.1.0" OutputItemType="Analyzer" />
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:
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 will have to be resolved manually!
Credit
| Product | Versions 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. |
-
.NETStandard 2.0
- Microsoft.CodeAnalysis.CSharp (>= 4.3.0)
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.5.2 | 2,261 | 9/15/2026 |
| 1.5.1 | 130 | 9/9/2026 |
| 1.5.0 | 119 | 9/7/2026 |
| 1.4.3 | 116 | 8/18/2026 |
| 1.4.2 | 115 | 8/18/2026 |
| 1.3.5 | 1,670 | 3/10/2026 |
| 1.3.4 | 149 | 2/25/2026 |
| 1.3.3 | 137 | 2/25/2026 |
| 1.3.2 | 131 | 2/25/2026 |
| 1.3.1 | 133 | 2/24/2026 |
| 1.3.0 | 597 | 2/9/2026 |
| 1.2.2 | 146 | 2/5/2026 |
| 1.2.1 | 148 | 2/3/2026 |
| 1.1.0 | 144 | 2/1/2026 |
| 1.0.2 | 144 | 1/21/2026 |
| 1.0.1 | 142 | 1/20/2026 |
| 1.0.0 | 140 | 1/20/2026 |
| 0.2.0 | 140 | 1/20/2026 |
0.2.0
- Support attaching [Adopt] to properties.
- Support events.
- Support nested interfaces.
0.1.0
- Initial version supporting attaching [Adopt] to members.