Skip to content

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.

License

Notifications You must be signed in to change notification settings

BlackWhiteYoshi/AutoInterface

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

65 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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:



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

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.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages