Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I enumerate a list of interfaces that are directly defined on an inheriting class?

Updated question given Andrew Hare's correct answer:

Given the following C# classes:

public class Bar : Foo, IDisposable
{
    // implementation of Bar and IDisposable
}

public class Foo : IEnumerable<int>
{
    // implementation of Foo and all its inherited interfaces
}

I want a method like the following that doesn't fail on the assertions (Note: you cannot change the assertions):

public void SomeMethod()
{
   // This doesn't work
   Type[] interfaces = typeof(Bar).GetInterfaces();

   Debug.Assert(interfaces != null);
   Debug.Assert(interfaces.Length == 1);
   Debug.Assert(interfaces[0] == typeof(IDisposable));
}

Can someone help by fixing this method so the assertions don't fail?

Calling typeof(Bar).GetInterfaces() doesn't work because it returns the entire interface hierarchy (i.e. interfaces variable contains IEnumerable<int>, IEnumerable, and IDisposable), not just the top level.

like image 786
Jordan Avatar asked Mar 25 '10 19:03

Jordan


2 Answers

Try this:

using System.Linq;    
public static class Extensions
{
    public static Type[] GetTopLevelInterfaces(this Type t)
    {
        Type[] allInterfaces = t.GetInterfaces();
        var selection = allInterfaces
            .Where(x => !allInterfaces.Any(y => y.GetInterfaces().Contains(x)))
            .Except(t.BaseType.GetInterfaces());
        return selection.ToArray();
    }
}

usage:

    private void Check(Type t, Type i)
    {
        var interfaces = t.GetTopLevelInterfaces();

        Debug.Assert(interfaces != null, "interfaces is null");
        Debug.Assert(interfaces.Length == 1, "length is not 1");
        Debug.Assert(interfaces[0] == i, "the expected interface was not found");

        System.Console.WriteLine("\n{0}", t.ToString());
        foreach (var intf in  interfaces)
            System.Console.WriteLine("  " + intf.ToString());

    }

    public void Run()
    {
        Check(typeof(Foo), typeof(IEnumerable<int>));
        Check(typeof(Bar), typeof(IDisposable));
    }

As noted elsewhere, this only works if the checked type explicitly implements a single interface. If you have more than one, then you need to change your Assert.

like image 53
Cheeso Avatar answered Oct 10 '22 02:10

Cheeso


Andrew Hare is correct that you cannot retrieve the specified list of interfaces using reflection. However you can find the "top-level" interfaces by excluding any interfaces that are implied by others. You could implement it like this:

Type[] allInterfaces = typeof(Foo).GetInterfaces();
Type[] interfaces = allInterfaces
   .Where(x => !allInterfaces.Any(y => y.GetInterfaces().Contains(x)))
   .ToArray();

This passes your assertions.

like image 44
Mark Byers Avatar answered Oct 10 '22 03:10

Mark Byers