Empty interfaces should be avoided as they do not provide any functional requirements for implementing classes.

## Why is this an issue?

Empty interfaces are either useless or used as a marker. Custom attributes are a better alternative to marker interfaces. See the How to fix it section for more information.

### Exceptions

This rule doesn’t raise in any of the following cases:

#### Aggregation of multiple interfaces

    public interface IAggregate: IComparable, IFormattable { } // Compliant: Aggregates two interfaces

#### Generic specialization

An empty interface with a single base interface is compliant as long as the resulting interface binds a generic parameter or constrains it.

    // Compliant: Bound to a concrete type
    public interface IStringEquatable: IEquatable<string> { }
    // Compliant: Specialized by type parameter constraint
    public interface ICreateableEquatable<T>: IEquatable<T> where T: new() { }

#### Custom attribute

An empty interface is compliant if a custom attribute is applied to the interface.

    [Obsolete]
    public interface ISorted { } // Compliant: An attribute is applied to the interface declaration

## How to fix it

Do any of the following to fix the issue:

- Add members to the interface
- Remove the useless interface
- Replace the usage as a marker interface with custom attributes

### Code examples

#### Noncompliant code example

The empty interface does not add any functionality.

    public interface IFoo // Noncompliant
    {

    }

#### Compliant solution

Add members to the interface to be compliant.

    public interface IFoo
    {
        void Bar();
    }

#### Noncompliant code example

A typical use case for marker interfaces is doing type inspection via reflection as shown below.

The `IIncludeFields` marker interface is used to configure the JSON serialization of an object.

    // An example marker interface
    public interface IIncludeFields { }

    public class OptInToIncludeFields: IIncludeFields { }

    Serialize(new OptInToIncludeFields());

    void Serialize<T>(T o)
    {
        // Use reflection to check if the interface is applied to the type
        var includeFields = o.GetType()
            .GetInterfaces().Any(i => i == typeof(IIncludeFields));
        var options = new JsonSerializerOptions()
        {
            // Take decisions based on the presence of the marker
            IncludeFields = includeFields,
        };
    }

The same example can be rewritten using custom attributes. This approach is preferable because it is more fine-grained, allows parameterization, and is more flexible in type hierarchies.

    // A custom attribute used as a marker
    [AttributeUsage(AttributeTargets.Class)]
    public sealed class IncludeFieldsAttribute: Attribute { }

    [IncludeFields]
    public class OptInToIncludeFields { }

    Serialize(new OptInToIncludeFields());

    void Serialize<T>(T o)
    {
        // Use reflection to check if the attribute is applied to the type
        var includeFields = o.GetType()
            .GetCustomAttributes(typeof(IncludeFieldsAttribute), inherit: true).Any();
        var options = new JsonSerializerOptions()
        {
            // Take decisions based on the presence of the marker
            IncludeFields = includeFields,
        };
    }

## Resources

### Documentation

- Microsoft Learn - Interfaces - define behavior for multiple types
- Wikipedia - Marker interface pattern
- Microsoft Learn - Writing custom attributes