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
{
}
CodePudding user response:
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.
CodePudding user response:
Are you sure you really need that? From a type perspective all the derived types implement that interface. Anyway if you really need that I don’t think there is a way to obtain this information using the System.Reflection (such as ImplementedInterfaces and GetInterfaces) as those include interfaces implemented by the base types as would things like is and as. If that is really required then you might need to use something like Mono.Cecil and read that from the actual metadata but then you have the overhead of reading in the file. See an example dotnetfiddle.