Search code examples
c#inheritanceinterface

Check if type implements interface directly. Not from inheritance


From list of types A, B, C, ANotState, BNotState I want to get A, B,C that are marked with the interface. But if do get interfaces from ANotState or BNotState I've got only isState which is inherited from C (from ANotState in BNotState case).

Is there a way to know if the interface is implemented directly?

public class Program
{
    public static void Main()
    {
        List<Type> types = new List<Type>{typeof(A), typeof(B), typeof(C), typeof(ANotState), typeof(BNotState)};
        
        //Now remove from list types that are not implementing isState interface directly which means ANotState and BNotState
    }
}

public interface isState{}


public class A : isState
{
    
}

public abstract class B : A, isState
{

}

public abstract class C : B, isState
{

}

public class ANotState : C
{

}

public class BNotState : ANotState
{

}

Solution

  • There's a solution which partially works. You can retrieve the interfaces implemented by the current type, then the interfaces implemented by its parent type, and then subtract those two sets. Like this:

    public HashSet<Type> GetDirectlyImplementedInterfaces<T>()
    {
        // interfaces of the given type T
        var allIfaces = typeof(T).GetInterfaces().ToHashSet();
        
        // interfaces of its base type
        var baseIfaces = typeof(T).BaseType.GetInterfaces().ToHashSet();
        
        // subtract
        allIfaces.ExceptWith(baseIfaces);
        return allIfaces;
    }
    

    However, it would work only for the first occurrence of specifying the given interface in the inheritance hierarchy. For example, in your case for A the method above returns isState, but for both B and C it doesn not, becase the interface was first implemented by their parent type, i.e. A.

    So, instead of using a marker interface, I'd recommend specifying the same information via a non-inheritable custom attribute:

    [AttributeUsage(AttributeTargets.Class, Inherited = false)]
    public class IsStateAttribute : Attribute { }
    

    Then you can go with a method like this to check if a type T represents a state or not:

    public bool CheckIsState<T>()
    {
        return typeof(T).GetCustomAttribute<IsStateAttribute>() != null;
    }
    

    This solutions correctly recognizes A, B and C as states, and ANotState and BNotState as not states.

    In case you'd need some members declared in the state interface, just combine both approaches.