DekGenius.com
[ Team LiB ] Previous Section Next Section

Recipe 7.7 An Advanced Interface Search Mechanism

Problem

You are searching for an interface using the Type class. However, complex interface searches are not available through the GetInterface and GetInterfaces methods of a Type object. The GetInterface method searches for an interface only by name (using a case-sensitive or -insensitive search), and the GetInterfaces method returns an array of all the interfaces implemented on a particular type. You want a more focused searching mechanism that might involve searching for interfaces that define a method with a specific signature or implemented interfaces that are loaded from the Global Assembly Cache (GAC). You need more flexible and more advanced searching for interfaces that does not involve creating your own interface search engine.

Solution

The FindInterfaces method of a Type object can be used along with a callback to perform complex searches of interfaces on a type. The following method will call a custom interface searching method, SearchInterfacesOfType:

using System;
using System.Reflection;

public class SearchType
{
    public void FindSpecificInterfaces( )
    {
        Type[] names = new Type[3] {Type.GetType("System.ICloneable"),
                       Type.GetType("System.Collections.ICollection"), 
                       Type.GetType("System.IAppDomainSetup")};
        Type[] interfaces = SearchInterfacesOfType(Type.GetType(
                            "System.Collections.ArrayList"), names);

        if (interfaces.Length > 0) 
        {
            Console.WriteLine("Matches found:");   
            for(int counter =0; counter < interfaces.Length; counter++)
            {
                Console.WriteLine("\tIFace Name: " + 
                                  interfaces[counter].ToString( ));
                Console.WriteLine("\tIFace Base Type: " + 
                                  interfaces[counter].BaseType);
                foreach (object attr in 
                         interfaces[counter].GetCustomAttributes(false))
                {
                    Console.WriteLine("\t\tIFace attr: " + attr.ToString( ));
                }
            }
        }
        else
        {
            Console.WriteLine("\t\tNo matches found");
        }
    }

    public Type[] SearchInterfacesOfType(Type searchedType, 
      Type[] ifaceNames)
    {
        TypeFilter filter = new TypeFilter(IfaceFilterCallback);
        Type[] interfaces =  
          searchedType.FindInterfaces(filter, ifaceNames);

        return (interfaces);
    }

    public bool IfaceFilterCallback(Type type, object criteria)
    {
        foreach (Type ifaceName in (Type[])criteria)
        {
            if(type.FullName == ifaceName.FullName)
            {
                return (true);
            }
        }

        return (false);
    }
}

The FindSpecificInterfaces method searches for any of the three interface types, contained in the Names array that are implemented by the System.Collections.ArrayList type.

The SearchinterfacesOfType method accepts a type (searchedType) on which to search for interfaces and an object (ifaceNames) that contains criteria for the search. For this method, the criterion is a Type array of interfaces. This method then calls the FindInterfaces method on the searchedType parameter and passes in a delegate and the Type array criteria of interfaces. (The delegate will be called back to for each found interface.) This method then returns an array of interface types that match the criterion.

The TypeFilter delegate, filter, defines the IfaceFilterCallback method to be called for each interface found on the searchedType object. The real power of this search mechanism lies in the IfaceFilterCallback callback method.

This callback searches for each of the interface types in the criteria array that is implemented by the searchedType parameter of the SearchInterfacesOfType method.

Discussion

Most complex member searches can be performed only through the use of the FindInterfaces method of a Type object. This method makes use of the TypeFilter delegate, which is passed to the filter parameter. This delegate is supplied by the FCL and allows an extra layer of filtering (of any type that you want) to occur. This delegate returns a Boolean value, where true indicates that the ifaceType object passed to this delegate should be included in the Type array that the FindInterfaces method returns; false indicates that this ifaceType object should not be included.

The FindInterfaces method will take into account all interfaces implemented by the type being searched as well as all of its base types when performing a search. In addition, if any of the interfaces implemented by any of these types also implements one or more interfaces, those interfaces are included in the search.


There are many ways to use this TypeFilter delegate to search for interfaces implemented on a type—here are just a few other searches that can be performed:

  • A filter to search for all implemented interfaces that are defined within a particular namespace (in this case, the System.Collections namespace):

    public bool IfaceFilterCallback(Type type, object criteria)
    {
        if (type.Namespace.Equals("System.Collections"))
        {
            return (true);
        }
        else
        {
            return (false);
        }
    }
  • A filter to search for all implemented interfaces that contain a method called Add, which returns an Int32 value:

    public bool IfaceFilterCallback(Type type, object criteria)
    {
        if (type.GetMethod("Add") != null && 
            type.GetMethod("Add").ReturnType == Type.GetType("System.Int32"))
        {
            return (true);
        }
        else
        {
            return (false);
        }
    }
  • A filter to search for all implemented interfaces that are loaded from the Global Assembly Cache (GAC):

    public bool IfaceFilterCallback(Type type, object criteria)
    {
        if (type.Assembly.GlobalAssemblyCache)
        {
            return (true);
        }
        else
        {
            return (false);
        }
    }
  • A filter to search for all implemented interfaces that are defined within an assembly with the version number 1.0.3300.0:

    public bool IfaceFilterCallback(Type type, object criteria)
    {
        if (type.Assembly.FullName.IndexOf("Version=1.0.3300.0") >= 0)
        {
            return (true);
        }
        else
        {
            return (false);
        }
    }

See Also

See Recipe 7.8; see the "Delegate Class" and "Type.FindInterfaces Method" topics in the MSDN documentation.

    [ Team LiB ] Previous Section Next Section