Recipe9.8.An Advanced Member Search Mechanism


Recipe 9.8. An Advanced Member Search Mechanism

Problem

You are searching for a member within a type using the Type class. However, complex member searches are not available through the GetMember and GetMembers methods of a Type object. The GetMember method searches for a member name only within a type limited by the set of BindingFlags used, and the GetMembers method searches for all members limited by the set of BindingFlags used. BindingFlags is an enumeration of various member types that can be searched. The BindingFlags related to this recipe are defined here:


DeclaredOnly

Include members declared at the same level of the Type's hierarchy in the search. No inherited members.


Default

Use no binding flags.


FlattenHierarchy

Include all static members in the inheritance hierarchy in the search (do not include static members of nested types in the search).


IgnoreCase

Perform a case-insensitive search.


Instance

Include instance members in the search.


NonPublic

Include nonpublic members in the search.


Public

Include public members in the search.


Static

Include static members in the search.

You need to create more flexible and advanced searches for members that do not involve creating your own member search engine, such as a code generation tool that uses preexisting assemblies as an input might need.

Solution

The FindMembers method of a Type object can be used, along with a callback, to create your own complex searches. The TestSearchMembers method shown in Example 9-9 will call your custom member-searching method, SearchMembers.

Example 9-9. Performing advanced member searches on a type

 using System;  using System.Reflection; public class SearchType {      public void TestSearchMembers( )      {         MemberInfo[] members = SearchMembersByReturnType(this.GetType( ),                                               Type.GetType("System.Int32"));         if (members.Length > 0)         {             Console.WriteLine("Matches found:");             // Display information for each match.             for(int counter = 0; counter < members.Length; counter++)             {                 Console.WriteLine("\tMember Name: " +                                    members[counter].ToString( ));                  Console.WriteLine("\tMember Type: " +                                    members[counter].MemberType);                  foreach (object attr in                     members[counter].GetCustomAttributes(false))             {                 Console.WriteLine("\t\tMember attr: "    +                     attr.ToString( ));             }         }     }     else     {         Console.WriteLine("\t\tNo matches found");     } } public MemberInfo[] SearchMembersByReturnType(Type searchedType,                                               Type returnType) {     // Delegate that compares the member's return type     // against the returnType parameter.     MemberFilter filterCallback = new MemberFilter(ReturnTypeFilter);          MemberInfo[] members = searchedType.FindMembers(MemberTypes.All,                 BindingFlags.Instance | BindingFlags.Public |                 BindingFlags.NonPublic | BindingFlags.Static,                 filterCallback,                 returnType);                      return (members); } private bool ReturnTypeFilter(MemberInfo member, object criteria) {     // Obtain the return type of either a method or property.     Type returnType = null;     if (member is MethodInfo)         returnType = ((MethodInfo)member).ReturnType;     else if (member is PropertyInfo)         returnType = ((PropertyInfo)member).PropertyType;     else         return (false);     // Match return type     if (returnType == ((Type)criteria))         return (true);     else         return (false); } 

This method will search for any member in the current type that has a return value of System.Int32.

The SearchMembersByReturnType method accepts a Type object in which to search and a string representation of the full name of a return type. This method simply calls the FindMembers method of the searchType object passed to it. Notice that the returnType parameter is passed to the FindMembers method as the last parameter.

The MemberFilter delegate, filterCallback, defines the ReturnTypeFilter method to be called for each member that meets the specified criteria of the FindMembers method (i.e., MemberTypes.All, BindingFlags.Instance, BindingFlags.Public, Binding-Flags.NonPublic, and BindingFlags.Static). The real power of this search mechanism lies in the ReturnTypeFilter callback method.

This callback method casts the member parameter to the correct member type (i.e., MethodInfo or PropertyInfo), obtains the return type, and compares that return type to the one passed in to the returnType parameter of the SearchMembersByReturnType method. A return value of TRue indicates that the return types matched; a false indicates they did not match.

Discussion

Most complex member searches can be made easier through the use of the FindMembers method of a Type object. This method returns an array of MemberInfo objects that contain all members that match the memberType, bindingAttr, and filterCriteria parameters.

This method makes use of the MemberFilter delegate, which is passed in to the filter parameter. This delegate is supplied by the FCL and allows an extra layer of member filtering to occur. This filtering can be anything you want. This delegate returns a Boolean value, where true indicates that the member object passed in to this delegate should be included in the MemberInfo array that the FindMembers method returns, and false indicates that this member object should not be included.

There are many ways to use this MemberFilter delegate to search for members within a type. Here are just a few other items that can be searched for:

  • A filter callback to search for fields marked as const:

     private bool ReturnTypeFilter(MemberInfo member, object criteria) {     if (member is FieldInfo)     {         if (((FieldInfo)member).IsLiteral)         {             return (true);         }         else         {             return (false);         }     }          return (false); } 

  • A filter callback to search for fields marked as readonly:

     private bool ReturnTypeFilter(MemberInfo member, object criteria) {     if (member is FieldInfo)     {         if (((FieldInfo)member).IsInitOnly)         {             return (true);         }         else         {             return (false);         }     }          return (false); } 

  • A filter to search for a read-only property:

     private bool ReturnTypeFilter(MemberInfo member, object criteria) {     if (member is PropertyInfo)     {         if (((PropertyInfo)member).CanRead && !((PropertyInfo)member).CanWrite)         {             return (true);         }         else         {             return (false);         }     }          return (false); } 

  • A filter to search for any methods that contain out parameters:

     private bool ReturnTypeFilter(MemberInfo member, object criteria) {     if (member is MethodInfo)     {         ParameterInfo[] params = ((MethodInfo)member).GetParameters( );         foreach (ParameterInfo param in params)         {             if (param.IsOut)             {                 return (true);             }         }                  return (false);     }     return (false); } 

  • A filter to search for any members that are marked with the System.ObsoleteAttribute attribute:

     private bool ReturnTypeFilter(MemberInfo member, object criteria) {     object[] attrs = member.GetCustomAttributes(false);     foreach (object attr in attrs)     {         if (attr.ToString( ).Equals("System.ObsoleteAttribute"))         {              return (true);         }     }     return (false); } 

See Also

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



C# Cookbook
Secure Programming Cookbook for C and C++: Recipes for Cryptography, Authentication, Input Validation & More
ISBN: 0596003943
EAN: 2147483647
Year: 2004
Pages: 424

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net