lucaslgt.InterfaceGenerator
1.0.0
dotnet add package lucaslgt.InterfaceGenerator --version 1.0.0
NuGet\Install-Package lucaslgt.InterfaceGenerator -Version 1.0.0
<PackageReference Include="lucaslgt.InterfaceGenerator" Version="1.0.0" />
<PackageVersion Include="lucaslgt.InterfaceGenerator" Version="1.0.0" />
<PackageReference Include="lucaslgt.InterfaceGenerator" />
paket add lucaslgt.InterfaceGenerator --version 1.0.0
#r "nuget: lucaslgt.InterfaceGenerator, 1.0.0"
#:package lucaslgt.InterfaceGenerator@1.0.0
#addin nuget:?package=lucaslgt.InterfaceGenerator&version=1.0.0
#tool nuget:?package=lucaslgt.InterfaceGenerator&version=1.0.0
InterfaceGenerator
Generate an interface from a class, and have the class implement it, with a single attribute.
using InterfaceGenerator;
[GenerateInterface]
public partial class Greeter
{
public string Hello(string name) => $"Hi {name}";
public int Count { get; set; }
}
generates
public partial class Greeter : global::IGreeter
{
}
public interface IGreeter
{
string Hello(string name);
int Count { get; set; }
}
so IGreeter can be registered in a container, mocked in a test, or handed to a caller, with
nothing to keep in sync by hand.
Install
dotnet add package lucaslgt.InterfaceGenerator
One package: the attributes are a normal reference, the generator ships inside it as an analyzer.
What ends up on the interface
Every member the annotated type declares itself that an interface can carry:
- public, non-static methods, properties, indexers and events;
- with their type parameters, constraints,
ref/out/in/paramsmodifiers, default values and nullable annotations preserved.
Left out: fields, constructors, operators, anything not public, anything static, overrides of
object members, compiler-synthesized members (a record's Equals, Deconstruct, …), and
members inherited from a base class — the interface describes what the type declares, not what
its bases happen to expose.
Only the accessors that are themselves public are declared, so
public string Name { get; private set; } becomes string Name { get; }.
Options
| Option | Effect |
|---|---|
Name |
Interface name. Defaults to the type name prefixed with I. |
Namespace |
Namespace to declare the interface in. Defaults to the type's namespace. |
Exclude |
Names to leave out; everything else is kept. |
Include |
Names to keep; everything else is left out. |
[GenerateInterface(Name = "IGreetingService", Exclude = [nameof(DumpState)])]
public partial class Greeter { /* ... */ }
Include and Exclude are mutually exclusive — setting both is an error (IG0004).
Names are matched by name, so a listed name takes every overload sharing it with it. Prefer
nameof over a literal: a name matching nothing is reported (IG0005), but nameof catches the
typo at the point of the rename instead. An indexer has no nameof, so it is listed by its
metadata name, "Item" unless [IndexerName] says otherwise.
Include = [] is an explicit empty list, not an unset option: it generates an empty interface.
Dependency injection
An assembly that references Microsoft.Extensions.DependencyInjection.Abstractions also gets an
IServiceCollection extension method registering every annotated type against the interface
generated for it:
new ServiceCollection()
.AddAcmeBillingServices() // Transient by default
.AddAcmeBillingServices(ServiceLifetime.Scoped); // or another default for this assembly
The method is named after the assembly (Acme.Billing → AddAcmeBillingServices) so that a
library and the application referencing it never offer two identically named extensions. Rename it,
or move it out of Microsoft.Extensions.DependencyInjection, with:
[assembly: GeneratedServiceRegistration(MethodName = "AddApplicationServices", Namespace = "Acme.Composition")]
The lifetime resolves in this order:
Lifetimeon the attribute, if set —[GenerateInterface(Lifetime = Lifetime.Singleton)];- otherwise the argument the extension method was called with;
- otherwise
Transient.
Lifetime.None leaves the type out of the registration entirely. Abstract types are never
registered; setting a lifetime on one is reported (IG0006).
Generic types are registered open — typeof(IRepository<>) to typeof(Repository<>) — so the
container closes them on demand.
Nothing is generated, and nothing is reported, in an assembly that does not reference the
DI abstractions: the generator stays usable for interfaces alone. Setting a Lifetime there is the
one case that warns (IG0007), since it is the only sign a container was expected.
Requirements
The annotated type must be partial and top-level. Records are supported; static types are not.
Diagnostics
| ID | Severity | Meaning |
|---|---|---|
| IG0001 | Error | The annotated type is not partial. |
| IG0002 | Error | The annotated type is nested inside another type. |
| IG0003 | Error | The annotated type is static. |
| IG0004 | Error | Include and Exclude are both set. |
| IG0005 | Warning | A listed name matches no eligible member. |
| IG0006 | Warning | A lifetime is set on an abstract type, which cannot be registered. |
| IG0007 | Warning | A lifetime is set, but the DI abstractions are not referenced. |
| 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
- No dependencies.
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.0 | 112 | 9/5/2026 |