AutoInterface by Black White Yoshi
NuGet / site data
Details
Info
Name: AutoInterface
AutoInterface is a source generator that generates an interface based on your class/struct. Basically, you write your class and get the corresponding interface for free.
Author: Black White Yoshi
NuGet: https://www.nuget.org/packages/AutoInterface/
You can find more details at https://github.com/BlackWhiteYoshi/AutoInterface
Original Readme
AutoInterface
AutoInterface is a source generator that generates an interface based on your class/struct.
Basically, you write your class and get the corresponding interface for free.
using AutoInterfaceAttributes;
[AutoInterface]
public class Example : IExample {
public int Number { get; private set; }
public Example() {
ResetNumber();
}
/// <summary>
/// some method description
/// </summary>
public int AddToNumber(int increase) {
Number += increase;
return Number;
}
private void ResetNumber() => Number = 0;
}
// <auto-generated/>
#pragma warning disable
#nullable enable annotations
using AutoInterfaceAttributes;
public partial interface IExample {
int Number { get; }
/// <summary>
/// some method description
/// </summary>
int AddToNumber(int increase);
}
AutoInterface supports:
- classes, records and structs
- all members (Method, Property, Indexer, Event)
- also explicit Interface members
- multiple attributes on same class
- summary of class/struct and members
- generic
- parameters for
Examples
AutoInterfaceAttribute on struct
using AutoInterfaceAttributes;
[AutoInterface]
public struct Point {
public int X { get; private set; }
public int Y { get; private set; }
public Point(int x, int y) => (X, Y) = (x, y);
}
// <auto-generated/>
#pragma warning disable
#nullable enable annotations
using AutoInterfaceAttributes;
public partial interface IPoint {
int X { get; }
int Y { get; }
}
AutoInterfaceAttribute with all kinds of members
using AutoInterfaceAttributes;
[AutoInterface]
public sealed class FullExample {
public void SomeMethod() { }
public int SomeProperty { get; init; }
public int this[int i] => i;
public event Action? someEvent;
public event Action SomeEvent { add { } remove { } }
}
// <auto-generated/>
#pragma warning disable
#nullable enable annotations
using AutoInterfaceAttributes;
public partial interface IFullExample {
void SomeMethod();
int SomeProperty { get; init; }
int this[int i] { get; }
event Action? someEvent;
event Action SomeEvent;
}
AutoInterfaceAttribute with explicit interface specifier
using AutoInterfaceAttributes;
[AutoInterface]
public sealed class ExplicitExample : IExplicitExample {
void IExplicitExample.SomeMethod() { }
int IExplicitExample.SomeProperty { get; init; }
int IExplicitExample.this[int i] => i;
event Action IExplicitExample.SomeEvent { add { } remove { } }
}
// <auto-generated/>
#pragma warning disable
#nullable enable annotations
using AutoInterfaceAttributes;
public partial interface IExplicitExample {
void SomeMethod();
int SomeProperty { get; init; }
int this[int i] { get; }
event Action SomeEvent;
}
multiple AutoInterfaceAttributes on same class
using AutoInterfaceAttributes;
[AutoInterface(Name = "IMultipleExample1")]
[AutoInterface(Name = "IMultipleExample2")]
public sealed class MultipleExample : IMultipleExample1, IMultipleExample2 {
public void SomeMethod() { }
int IMultipleExample1.PropertyFirst { get; set; }
string IMultipleExample2.PropertySecond { get; set; }
}
// <auto-generated/>
#pragma warning disable
#nullable enable annotations
using AutoInterfaceAttributes;
public partial interface IMultipleExample1 {
void SomeMethod();
int PropertyFirst { get; set; }
}
...
// <auto-generated/>
#pragma warning disable
#nullable enable annotations
using AutoInterfaceAttributes;
public partial interface IMultipleExample2 {
void SomeMethod();
string PropertySecond { get; set; }
}
AutoInterfaceAttribute with summary documentation
using AutoInterfaceAttributes;
/// <summary>
/// my class description
/// </summary>
[AutoInterface]
public sealed class SummaryExample {
/// <summary>
/// some method description
/// </summary>
public void SomeMethod() { }
}
// <auto-generated/>
#pragma warning disable
#nullable enable annotations
using AutoInterfaceAttributes;
/// <summary>
/// my class description
/// </summary>
public partial interface ISummaryExample {
/// <summary>
/// some method description
/// </summary>
void SomeMethod();
}
AutoInterfaceAttribute with generic class
using AutoInterfaceAttributes;
[AutoInterface]
public sealed class GenericExample<T> {
public T Identity(T parameter) => parameter;
}
// <auto-generated/>
#pragma warning disable
#nullable enable annotations
using AutoInterfaceAttributes;
public partial interface IGenericExample<T> {
T Identity(T parameter);
}
Parameter
Name
Type: string
Default: $"I{ClassName}"
If you want another name for your interface, put it here.
using AutoInterfaceAttributes;
[AutoInterface(Name = "NewName")]
public sealed class Example;
// <auto-generated/>
#pragma warning disable
#nullable enable annotations
using AutoInterfaceAttributes;
public partial interface NewName {}
Modifier
Type: string
Default: "public partial"
If you want another visible modifier or make the interface non-partial or unsafe, you can do this here.
using AutoInterfaceAttributes;
[AutoInterface(Modifier = "internal")]
public sealed class Example;
// <auto-generated/>
#pragma warning disable
#nullable enable annotations
using AutoInterfaceAttributes;
internal interface IExample {}
Namespace
Type: string
Default: $"{ClassNamespace}"
When the generated interface should live in a specific namespace, you can specify it here.
For global namespace, use an empty string.
using AutoInterfaceAttributes;
namespace MyApp.Core;
[AutoInterface(Namespace = "MyApp.Utils")]
public sealed class Example;
// <auto-generated/>
#pragma warning disable
#nullable enable annotations
using AutoInterfaceAttributes;
namespace MyApp.Utils;
public partial interface IExample {}
Inheritance
Type: Type[]
Default: []
If the generated interface should inherit from one or more other interfaces, you can list them here.
using AutoInterfaceAttributes;
[AutoInterface(Inheritance = [typeof(ICore)])]
public sealed class Example;
public partial interface ICore { ... }
// <auto-generated/>
#pragma warning disable
#nullable enable annotations
using AutoInterfaceAttributes;
public partial interface IExample : ICore {}
Nested
Type: string[]
Default: []
When the interface should be nested inside other classes, structs or interfaces, declare them here.
using AutoInterfaceAttributes;
[AutoInterface(Nested = ["public partial class MyWrapper", "public partial interface OuterInterface"])]
public sealed class Example {
public void SomeMethod() { }
}
// <auto-generated/>
#pragma warning disable
#nullable enable annotations
using AutoInterfaceAttributes;
public partial class MyWrapper {
public partial interface OuterInterface {
public partial interface IExample {
void SomeMethod();
}
}
}
StaticMembers
Type: bool
Default: false
Normally, static members are just ignored.
However, an interface can contain static members as a "static abstract" member.
To accept static members to generate "static abstract" members, set this flag to true.
using AutoInterfaceAttributes;
[AutoInterface(StaticMembers = true)]
public sealed class Example {
public static void SomeMethod() { }
}
// <auto-generated/>
#pragma warning disable
#nullable enable annotations
using AutoInterfaceAttributes;
public partial interface IExample {
static abstract void SomeMethod();
}
Access Modifier
When you want to set the visibility of a specific member, you can decorate it with a [AutoInterfaceVisibility...] attribute.
There are 5 different Visibility attribute:
- [AutoInterfaceVisibilityPublic]
- [AutoInterfaceVisibilityInternal]
- [AutoInterfaceVisibilityProtected]
- [AutoInterfaceVisibilityProtectedInternal]
- [AutoInterfaceVisibilityPrivateProtected]
using AutoInterfaceAttributes;
[AutoInterface]
public sealed class Example : IExample {
[AutoInterfaceVisibilityPublic]
public void PublicMethod() { }
[AutoInterfaceVisibilityInternal]
void IExample.InternalMethod() { }
[AutoInterfaceVisibilityProtected]
void IExample.ProtectedMethod() { }
[AutoInterfaceVisibilityProtectedInternal]
void IExample.ProtectedInternalMethod() { }
[AutoInterfaceVisibilityPrivateProtected]
void IExample.PrivateProtectedMethod() { }
}
// <auto-generated/>
#pragma warning disable
#nullable enable annotations
using AutoInterfaceAttributes;
public partial interface IExample {
[AutoInterfaceVisibilityPublic]
public void PublicMethod();
[AutoInterfaceVisibilityInternal]
internal void InternalMethod();
[AutoInterfaceVisibilityProtected]
protected void ProtectedMethod();
[AutoInterfaceVisibilityProtectedInternal]
protected internal void ProtectedInternalMethod();
[AutoInterfaceVisibilityPrivateProtected]
private protected void PrivateProtectedMethod();
}
Note:
The access modifiers private and file are not possible,
because private members needs an implementation and file members would not be visible to the outside.
IgnoreAutoInterfaceAttribute
When you want a specific member to be ignored by the generator, you can decorate it with [IgnoreAutoInterface].
using AutoInterfaceAttributes;
[AutoInterface]
public sealed class Example {
[IgnoreAutoInterface]
public void SomeMethod() { }
}
// <auto-generated/>
#pragma warning disable
#nullable enable annotations
using AutoInterfaceAttributes;
public partial interface IExample {}
Disable Attribute Generation
You can disable the generation of the attributes by defining a constant for your compilation:
<PropertyGroup>
<DefineConstants>AUTOINTERFACE_EXCLUDE_ATTRIBUTES</DefineConstants>
</PropertyGroup>
This functionality is specific for the use case when you have a project referencing another project, both projects using this generator and you have InternalsVisibleTo enabled. In that case you have the attributes defined twice in your referencing project and you get a warning about that. By defining this constant in your referencing project, you prevent one generation, so the attributes are only defined once in the referenced project.
Remarks
Using-statements will always be placed on the top, so using not fully-qualified using-statements might cause compile errors.
using AutoInterfaceAttributes;
namespace System.Collections {
using Generic; // <-- refers to "System.Collections.Generic"
[AutoInterface]
public sealed class Example;
}
// ...
// <auto-generated/>
#pragma warning disable
#nullable enable annotations
using Generic; // <-- refers to "Generic"
using AutoInterfaceAttributes;
public partial interface IExample {}
You also should not use not fully-qualified using-statements in the first place, because they can be ambiguous. By introducing an additional namespace, the referring of a not fully-qualified using-statement might change and your application breaks at unrelated places. Just put your using statements at the top.
About
generating interface from a class
How to use
Example (source csproj, source files)
- CSharp Project
- Program.cs
- Department.cs
- Employee.cs
This is the CSharp Project that references AutoInterface
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AutoInterface" Version="2.4.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>
This is the use of AutoInterface in Program.cs
using NullInterface;
Console.WriteLine("Hello, World!");
Console.WriteLine("Hello, World!");
IDepartment department = new Department();
department.Name = "IT";
IEmployee employee = new Employee();
employee.FirstName = "Andrei";
employee.Department = department;
Console.WriteLine(employee.FirstName);
Console.WriteLine(employee.Department.Name);
Console.WriteLine(employee.GetFullNameAndDepartment(" - "));
This is the use of AutoInterface in Department.cs
using AutoInterfaceAttributes;
namespace NullInterface;
[AutoInterface]
public class Department : IDepartment
{
public string Name { get; set; } = string.Empty;
}
This is the use of AutoInterface in Employee.cs
using AutoInterfaceAttributes;
namespace NullInterface;
[AutoInterface]
public class Employee: IEmployee
{
public string FirstName { get; set; } = string.Empty;
public string LastName { get; set; } = string.Empty;
public IDepartment Department { get; set; }
public string GetFullName()=> $"{FirstName} {LastName}";
public string GetFullNameAndDepartment(string separator)=> $"{GetFullName()}{separator}{ Department?.Name}";
}
Generated Files
Those are taken from $(BaseIntermediateOutputPath)\GX
- AutoInterfaceAttribute.g.cs
- AutoInterfaceVisibilityInternalAttribute.g.cs
- AutoInterfaceVisibilityPrivateProtectedAttribute.g.cs
- AutoInterfaceVisibilityProtectedAttribute.g.cs
- AutoInterfaceVisibilityProtectedInternalAttribute.g.cs
- AutoInterfaceVisibilityPublicAttribute.g.cs
- IDepartment_NullInterface.Department_Department.cs.g.cs
- IDepartment_NullInterface.Department_IDepartment.cs.g.cs
- IEmployee_NullInterface.Employee_Employee.cs.g.cs
- IgnoreAutoInterfaceAttribute.g.cs
// <auto-generated/>
#pragma warning disable
#nullable enable annotations
#if !AUTOINTERFACE_EXCLUDE_ATTRIBUTES
using System;
namespace AutoInterfaceAttributes;
/// <summary>
/// Generates an interface for the decorated class/struct.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)]
[System.CodeDom.Compiler.GeneratedCodeAttribute("AutoInterface", "2.4.0")]
internal sealed class AutoInterfaceAttribute : Attribute {
/// <summary>
/// <para>The name of the generated interface.</para>
/// <para>Default is "I{ClassName}"</para>
/// </summary>
public string Name { get; init; }
/// <summary>
/// <para>The modifier(s) for the interface.</para>
/// <para>Deault is "public partial"</para>
/// </summary>
public string Modifier { get; init; }
/// <summary>
/// <para>The namespace declaration for the interface.</para>
/// <para>If empty string, no namespace directive will be used (global namespace).<br />
/// Default (if not present) it will be mapped to the same namespace as the namespace of the class/struct.</para>
/// </summary>
public string Namespace { get; init; }
/// <summary>
/// <para>interface inheritance: Name(s) of interfaces this interface will inherit.</para>
/// <para>Default is Array.Empty</para>
/// </summary>
public Type[] Inheritance { get; init; }
/// <summary>
/// <para>
/// The Classes, structs or interfaces containing the generated interface.<br />
/// e.g. ["public sealed partial class Example"] will wrap the interface with that expression.
/// </para>
/// <para>Default is Array.Empty</para>
/// </summary>
public string[] Nested { get; init; }
/// <summary>
/// <para>If enabled, static members get accepted and are generating "static abstract" members.</para>
/// <para>Default is false</para>
/// </summary>
public bool StaticMembers { get; init; }
}
#endif
// <auto-generated/>
#pragma warning disable
#nullable enable annotations
#if !AUTOINTERFACE_EXCLUDE_ATTRIBUTES
using System;
namespace AutoInterfaceAttributes;
/// <summary>
/// Adds a "internal" access modifier to the interface member.
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Event)]
[System.CodeDom.Compiler.GeneratedCodeAttribute("AutoInterface", "2.4.0")]
internal sealed class AutoInterfaceVisibilityInternal : Attribute { }
#endif
// <auto-generated/>
#pragma warning disable
#nullable enable annotations
#if !AUTOINTERFACE_EXCLUDE_ATTRIBUTES
using System;
namespace AutoInterfaceAttributes;
/// <summary>
/// Adds a "private protected" access modifier to the interface member.
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Event)]
[System.CodeDom.Compiler.GeneratedCodeAttribute("AutoInterface", "2.4.0")]
internal sealed class AutoInterfaceVisibilityPrivateProtected : Attribute { }
#endif
// <auto-generated/>
#pragma warning disable
#nullable enable annotations
#if !AUTOINTERFACE_EXCLUDE_ATTRIBUTES
using System;
namespace AutoInterfaceAttributes;
/// <summary>
/// Adds a "protected" access modifier to the interface member.
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Event)]
[System.CodeDom.Compiler.GeneratedCodeAttribute("AutoInterface", "2.4.0")]
internal sealed class AutoInterfaceVisibilityProtected : Attribute { }
#endif
// <auto-generated/>
#pragma warning disable
#nullable enable annotations
#if !AUTOINTERFACE_EXCLUDE_ATTRIBUTES
using System;
namespace AutoInterfaceAttributes;
/// <summary>
/// Adds a "protected internal" access modifier to the interface member.
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Event)]
[System.CodeDom.Compiler.GeneratedCodeAttribute("AutoInterface", "2.4.0")]
internal sealed class AutoInterfaceVisibilityProtectedInternal : Attribute { }
#endif
// <auto-generated/>
#pragma warning disable
#nullable enable annotations
#if !AUTOINTERFACE_EXCLUDE_ATTRIBUTES
using System;
namespace AutoInterfaceAttributes;
/// <summary>
/// Adds a "public" access modifier to the interface member.
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Event)]
[System.CodeDom.Compiler.GeneratedCodeAttribute("AutoInterface", "2.4.0")]
internal sealed class AutoInterfaceVisibilityPublic : Attribute { }
#endif
// <auto-generated/>
#pragma warning disable
#nullable enable annotations
using AutoInterfaceAttributes;
namespace NullInterface;
public partial interface IDepartment {
string Name { get; set; }
}
// <auto-generated/>
#pragma warning disable
#nullable enable annotations
namespace NullInterface;
public partial interface IDepartment {
string Name { get; set; }
}
// <auto-generated/>
#pragma warning disable
#nullable enable annotations
using AutoInterfaceAttributes;
namespace NullInterface;
public partial interface IEmployee {
string FirstName { get; set; }
string LastName { get; set; }
IDepartment Department { get; set; }
string GetFullName();
string GetFullNameAndDepartment(string separator);
}
// <auto-generated/>
#pragma warning disable
#nullable enable annotations
#if !AUTOINTERFACE_EXCLUDE_ATTRIBUTES
using System;
namespace AutoInterfaceAttributes;
/// <summary>
/// The decorated member will be Ignored by the generator.
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Event)]
[System.CodeDom.Compiler.GeneratedCodeAttribute("AutoInterface", "2.4.0")]
internal sealed class IgnoreAutoInterfaceAttribute : Attribute { }
#endif
Useful
Download Example (.NET C#)
Share AutoInterface
https://ignatandrei.github.io/RSCG_Examples/v2/docs/AutoInterface