Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

Retrieving only Declared Interfaces with .NET


:P
On this page:

Aarrgh… here’s a task that should be easy but is dreadfully convoluted: Using Reflection, try and retrieve only the declared Interfaces of a type. By declared I mean only those implemented by the type, not interfaces Inherited. Reflection makes retrieval of types and interfaces very easy with the GetInterfaces() method. Unfortunately GetInterfaces() doesn’t provide a lot of flexibility in what gets retrieved.

 

In Help Builder, one of the things the Type and Assembly importing does, is retrieve all types defined and it retrieve the inheritance list of classes as well as the interface implemented.

 

Help Builder does all sorts of stuff with Reflection to retrieve type information including methods, fields, properties events etc. Reflection is very powerful and it makes it really straight forward to retrieve all of this information. What’s even nicer is that in most cases you can apply filters with BindingFlags that let you determine exactly what to return.

 

For example, in Help Builder I give people the choice when importing their classes to only import members that are declared at the current class hierarchy level. For example, when importing declared only types I can do:

 

this.RetrievalFlags =   BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;

 

These BindingFlags can be applied to GetMembers() and GetMethods(),GetFields(), GetProperties() etc. and it works great.

 

You can also retrieve Interfaces with the GetInterfaces() method. GetInterfaces() returns a complete list of interfaces that are implemented by the class – which if you subclass any control based classes can be a damn long list of interfaces! In Help Builder this is just not right:

 

 

What I really want on my imports is to only show the actively declared interfaces of the class I’m importing.

Unfortunately this GetInterfaces() does not support these binding flags and the Interfaces returned give no indication at which level they are implemented.

 

Two hours of playing around with a number of different approaches (Comparing the base Interface and the current interface, running through each interface looking for matching methods in my declared methods etc.) Besides being ugly they are not solving the problem completely.

 

It turns out there’s a better way that’s fairly easy and not totally resource intensive using an InterfaceMapping. Yeah, I had no idea what an InterfaceMap is either <g>. In fact, I’m still not quite sure what this class does beyond the one thing I need it for – it holds references to a bunch of information that I can get from the Type and the Interface easily on my own.

 

Anyway the following C# code demonstrates how to retrieve a list of interfaces from a type and then retrieve only the implemented interfaces:

 

Type[] Implementations = loType.GetInterfaces();

 

if (Implementations!=null)

{

      foreach(Type Implementation in Implementations)

      {

            // *** This will work AS LONG AS THE INTERFACE HAS AT LEAST ONE MEMBER!

            // *** This will give not show an 'empty' placeholder interface

            // *** Can't figure out a better way to do this...

            InterfaceMapping im = loType.GetInterfaceMap(Implementation);

            if (im.TargetMethods.Length >0 &&
                im.TargetMethods[0].DeclaringType == loType)

                loObject.cImplements += Implementation.Name + ",";

      }

      if (loObject.cImplements != "")

            loObject.cImplements = loObject.cImplements.Substring(0,loObject.cImplements.Length-1);

}

 

Now unfortunately this is also not a 100% solution as it looks at the TargetMethods collection. The assumption here is that the interface has at least one method or property. If you have a placeholder interface that defines no properties or methods there won’t be any TargetMethods and this code will not find this interface as a declared interface.

 

Maybe there's a better way, but while searching I couldn't find a solution, only a few others asking the same question. If anyone has a better solution I’m all ears. In the meantime this handles the majority of cases and I can look forward to a much smaller Interface display in Help Builder.

 

Now the interface list is imported correctly:

 

 

 

BTW, if you are a Help Builder user you’ll notice that there have been a number of enhancements to the .NET class importer. A couple of the new features – that admittedly should have been there before – are links to the inheritance list, including MSDN links to .NET types, proper type declarations instead of the IDL names previously used. In addition, the XML Doc parser now properly parses <see> CREF tags and links them either to internal topics or MSDN topics. I've also updated the layout of the stylesheet and the base templates to be closer to MSDN style (although they aren't using the exact same style). Yeah, I know – just slowly catching up to NDoc, but remember Component documentation is only part of Help Builder as it is a full Help and documentation development environment that allows full editing for content. Developer docs need more than just imported documentation that comes from source code.

 

These new features will be in the next drop in the next few days.


The Voices of Reason


 

PilotBob
March 03, 2005

# re: Retrieving only Declared Interfaces with .NET

Since Dot Net doesn't have multiple inheritence, can't you just get the interfaces the parent supports, and compare the two. Can that the child exports but the parent doesn't were implemented in the child.

Rick Strahl
March 03, 2005

# re: Retrieving only Declared Interfaces with .NET

That's the first thing I thought of, but that doesn't work because you can re-implement an interface at a higher level in the hierarchy. So you may have for example you might have ISerializable implemented in the base and the parent which is actually quite common.

Given all that's involved that wouldn't be any easier either <g>...

Rick Strahl's WebLog
March 03, 2005

# IsFinal and IsSealed in Reflection

When parsing through methods with Reflection in a number of cases it turns out that both IsVirtual and IsSealed are set at the same time?

Rick Strahl's WebLog
March 07, 2005

# Help Builder 4.05 improves .NET support

Help Builder 4.05 was supposed to be a very minor update. Instead user feedback of the last few days inspired a number of fixes and improvements that amount to a fairly significant update. Here are some additional details and a behind the scenes look.

Rick Strahl's Web Log
February 17, 2007

# Help Builder 4.05 improves .NET support - Rick Strahl's Web Log

Help Builder 4.05 was supposed to be a very minor update. Instead user feedback of the last few days inspired a number of fixes and improvements that amount to a fairly significant update. Here are some additional details and a behind the scenes look.

Mike
December 02, 2008

# re: Retrieving only Declared Interfaces with .NET

This technique does not work for a class where you implement the interface on a class but then override the methods on the derived class.

class A : B
{
public override void Add(...)
}

abstract B : IDictionary
{
abstract void Add(..)
...
}

Using your technique, it will say that A implements IDictionary. Maybe not the end of the world depending on what you are doing, but something to be aware of.

Ruud Duivenvoorden
October 20, 2010

# re: Retrieving only Declared Interfaces with .NET

Hi,

How about:

Type[] flattenInterfacesOnThis = dotNetType.GetInterfaces();
Type[] flattenInterfacesOnBase = dotNetType.BaseType.GetInterfaces();
Type[] declaredInterfacesOnThis = flattenInterfacesOnThis.Except(flattenInterfacesOnBase).ToArray();


have fun with it.

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024