22.2. Browsing and Querying Members

As you have seen, with 124 methods to browse it can quickly become tedious trying to find the right method with the right signature. Unlike Java, C# provides an API that gives you methods for selecting and searching for a set of members based on certain criteria. The criteria you specify are typically member modifiers that precede the member definition; examples include static, public, and private methods, fields, and constructors.

Listing 22.2 shows how to browse and query fields and methods of any C# type. The FindMembers method of the MemberInfo class can be used to narrow the search. The parameters of this method are MemberTypes, BindingFlags, MemberFilter, and Object. Let's explore the meanings of these parameters in further detail:

  • MemberTypes is an object that indicates the type of the member to search for. These include All, Constructor, Custom, Event, Field, Method, Nestedtype, Property, and TypeInfo. We will also use the MemberTypes.Method to find a method. BindingFlags is an enumeration that controls the way searches are conducted by reflection. There are a great many BindingFlag values, including IgnoreCase, Instance, Public, Static, and so forth. The BindingFlags default member indicates no binding flag, which is what we want because we do not want to restrict the binding.

  • MemberFilter is a delegate that is used to filter the list of members in the MemberInfo array of objects. The filter we'll use is Type.FilterName, a field of the Type class used for filtering on a name.

  • Object is a string value that will be used by the filter. In this case we pass "Get*" to match only those methods that begin with the letters Get.

Listing 22.2. Browsing and Querying Fields and Methods of a Type (C#)
using System;
using System.Reflection;

class FieldTest {

  public static void Main(string[] args) {

    Type t = Type.GetType(args[0]);
    QueryFields(t);
    QueryMethods(t);
  }

  private static void QueryFields(Type t) {
    //Get Fields
    FieldInfo[] f = t.GetFields();
    Display("Get Fields ", f);
    //default fields
    f = t.GetFields(BindingFlags.Default);
    Display("Default ", f);
    //Find all public instance fields
    f = t.GetFields(BindingFlags.Public | BindingFlags.
                        Instance);
    Display("Public and Instance ", f);
    //Find all nonpublic instance fields
    f = t.GetFields(BindingFlags.Instance |
                        BindingFlags.NonPublic);
    Display("Non Public and Instance ", f);
    //Find all public static fields
    f = t.GetFields(BindingFlags.Static |BindingFlags.Public);
    Display("Static and Public ", f);
    //Find all nonpublic static fields
    f = t.GetFields(BindingFlags.Static | BindingFlags.
                        NonPublic);
    Display("Static and NonPublic ", f);
    //Find all public declared-only fields
    f = t.GetFields(BindingFlags.DeclaredOnly |
                               BindingFlags.NonPublic);
    Display("Public and DeclaredOnly ", f);
    //Find all fields
    MemberInfo[] m =
      t.FindMembers(MemberTypes.Field,
        BindingFlags.Default,Type.FilterName, "Get*");
    Display ("Found Field members", m);
  }

  private static void QueryMethods(Type t) {
    //Get Methods
    MethodInfo[] f = t.GetMethods();
    Display("Get Methods ", f);
    //default methods
    f = t.GetMethods(BindingFlags.Default);
    Display("Default ", f);
    //Find all public instance methods
    f = t.GetMethods(BindingFlags.Public | BindingFlags.
                        Instance);
    Display("Public and Instance ", f);
    //Find all nonpublic instance methods
    f = t.GetMethods(BindingFlags.Instance |
                        BindingFlags.NonPublic);
    Display("Non Public and Instance ", f);
    //Find all public static methods
    f = t.GetMethods(BindingFlags.Static | BindingFlags.
                        Public);
    Display("Static and Public ", f);
    //Find all nonpublic static methods
    f = t.GetMethods(BindingFlags.Static | BindingFlags.Non
                        Public);
    Display("Static and NonPublic ", f);
    //Find all public declared only methods
    f = t.GetMethods(BindingFlags.DeclaredOnly |
                               BindingFlags.NonPublic);
    Display("Public and DeclaredOnly ", f);
    //Find all methods
    MemberInfo[] m =
          t.FindMembers(MemberTypes.Method,
            BindingFlags.Default,Type.FilterName, "Get*");
    Display ("Found Method members", m);
  }

  private static void Display(String msg, MemberInfo[] fields) {
    Console.WriteLine ("--------");
    Console.WriteLine (msg);
    Console.WriteLine ("--------");
    foreach (MemberInfo f in fields) {
      Console.WriteLine(f.Name);
    }
  }

}

To run Listing 22.2 we pass a command line parameter:

C:>Reflection System.Type

Here is an excerpt of the output of Listing 22.2:

--------
Get Fields
--------
FilterAttribute
FilterName
FilterNameIgnoreCase
Missing
Delimiter
EmptyTypes
...
--------
Static and NonPublic
--------
ResolveTypeRelativeTo
ResolveTypeRelativeTo
ResolveTypeRelativeToBaseTypes
--------

To print only the name, we treat the FieldInfo[] and MethodInfo[] collections using the generic MemberInfo[]. We can find out the type of the member using the MemberType property of the MemberInfo class.

Listing 22.2 deals with fetching a collection of members (fields or methods) either by browsing or calling the FindMembers method. Sometimes, though, it is necessary to zoom into a particular method. Listing 22.3 shows how we can use GetMethod to find a particular method. The same calls can be used to get to a specific field, property, or constructor of a type. Using reflection to get a particular member of a type requires knowledge of the existence of that member; otherwise, an exception will occur.

Listing 22.3. Getting Specific Methods of a Type (C#)
using System;
using System.Reflection;

class SpecificMethodTest {

  public static void Main(string[] args) {

    Type t = typeof (System.String);
    DoMethod(t);
  }

  private static void DoMethod(Type t) {
    //Getting a method using only the name.
    //This will give an exception
    //Because ToUpper is overloaded. The call below is
    //confusing as to which
    //overloaded method is to be returned.
    MethodInfo m = null;
    try {
      m = t.GetMethod("ToUpper");
    } catch (Exception e) {
      Console.WriteLine(e.Message);
    }
    //Getting a method using only the name. The name
    //is case-sensitive, so the exact name is needed.
    //The method called cannot be overloaded.
    m = t.GetMethod("Remove");
    Console.WriteLine("Default Remove method "  );
    //Getting an overloaded method using the name and the
    //the type of parameters it takes.
    Type[] ta = new Type [] {typeof (int),typeof (char)};
    m = t.GetMethod("PadLeft", ta);
    Console.WriteLine("PadLeft method with params "  );
    //Call a method that takes no parameters
    Type[] noparams = new Type [0];
    m = t.GetMethod("ToUpper", noparams);
    Console.WriteLine("ToUpper method with no params "  );
    //Call a method that takes no parameters
    m = t.GetMethod("Remove", noparams);
    Console.WriteLine("Remove method with no params
                                                  "+(m==null));
  }

}

The output of Listing 22.3 is as follows:

Ambiguous match found.
Default Remove method System.String Remove(Int32, Int32)
PadLeft method with params System.String PadLeft(Int32, Char)
ToUpper method with no params System.String ToUpper()
Remove method with no params True

The following excerpt of Listing 22.3 is particularly interesting. We know that there is only one Remove method in the System.String class, and it takes two parameters, and we are attempting to get a Remove method with no parameters.

//Call a method that takes no parameters
m = t.GetMethod("Remove", noparams);
Console.WriteLine("Remove method with no params "+(m==null));

Such a method does not exist in the System.String API, and, instead of throwing an exception, the runtime returns a “null” MethodInfo object. This can be a little confusing to Java programmers, who expect an exception to be thrown if a method is not found.

Note that in the reflection API, the search and query methods—such as GetMethod(s), GetConstructor(s), GetMember(s), GetField(s), and GetProperties—do not throw a NoSuchMemberException or a derivative; instead, they return a null object if the member is not found or defined for that type. This approach is somewhat different from that of the Java world, where a checked exception (java.lang.NoSuchMethodException or java.lang.NoSuchFieldException) gets thrown when a member (field, method, or constructor) cannot be found for a particular class. We will leave it to the language gurus to debate which is philosophically more sound: returning null or throwing an exception. Java programmers who are used to using exceptions for control flow should be aware of this subtle difference in C#.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.216.138.97