22.3. Invoking Methods and Setting Fields and Properties

So far we have seen how to query, search, and retrieve specific type members or a collection of type members. The true power of reflection lies in invoking those methods and constructors and setting those properties and fields. Listing 22.4 shows invoke operations on the System.String class.

Listing 22.4. Invoke Operations Using Reflection (C#)
using System;
using System.Reflection;

class InvocationTest {

  public static void Main(string[] args) {

    Type t = typeof (System.String);
    CallConstructor(t);
    CallMethod(t);
    GetProperty(t);
  }

  private static void CallConstructor(Type t) {
    //Tried to get the default no-args public constructor.
    // String s = new String(char[] c);
    ConstructorInfo constructor =null;
    constructor = t.GetConstructor(new Type[] {typeof
                                                    (Char[])});
    Char[] carr = new Char[] { 's', 'u', 'g', 'a', 'r' };
    object[] args = new object[1] {carr} ;
    try {
      Console.WriteLine(constructor.Invoke(args));
    } catch (Exception e) {
      Console.WriteLine(e.StackTrace);
    }
  }

  private static void CallMethod(Type t) {
    MethodInfo method =null;
    String target = "sugarless";
    method = t.GetMethod("Remove");
    object[] args = new object[] {5,4};
    Console.WriteLine(method.Invoke(target, args));
  }

  private static void GetProperty(Type t) {
    PropertyInfo property = null;
    property = t.GetProperty("Length");
    String args = "floccinaucinihipilification";
    Console.WriteLine(property.GetValue(args, null));
  }
}

The output of Listing 22.4 is as follows:

sugar
sugar
27

To truly appreciate the power of reflection, we will write a utility that lets us query in-memory collections. The System.Collections classes (see Chapter 14) are type-agnostic, so they can be used to hold objects of any type. Using reflection, we can ask for objects from a collection meeting specific criteria. For simplicity we assume that it is a homogeneous collection (one that contains only one type of an object). Listing 22.5 shows a sample class whose objects we will store in the collection.

Listing 22.5. The Person Class (C#)
using System.Text;

public class Person {

  private string firstname;
  private string lastname;
  private int age;
  private float salary;
  private bool male;

  public Person (string fname, string lname,
             int age, float salary, bool male) {
    this.firstname = fname;
    this.lastname = lname;
    this.age = age;
    this.salary = salary;
    this.male = male;
  }

  public override string ToString() {
    StringBuilder builder = new StringBuilder();

      builder.Append(firstname+","+lastname+",
                       "+age+","+salary+","  ale);
    return builder.ToString();
  }
}

The basic idea behind the QueryList collection is to be able to query objects from it that meet specific criteria. For example, if we were to store only Person objects in the list, then we could ask for Persons meeting specific criteria (for example, all persons with firstname Jack, all persons with salary > $60000, all males under 40 years of age). Listing 22.6 shows the bulk of the QueryList class.

Listing 22.6. The QueryList Class (C#)
using System;
using System.Collections;
using System.Reflection;
using System.Text;
public class QueryList : ArrayList {

public enum Operation : int {
    OBJECT_EQUALS = 1,
    PRIMITIVE_EQUALS,
    LESS_THAN_OR_EQUAL,
    GREATER_THAN_OR_EQUAL,
    LESS_THAN,
    GREATER_THAN,
    NOT_EQUALS
  }

  public QueryList() : base() {
  }
  public QueryList(ICollection coll): base(coll) {
  }
  public QueryList(int size): base(size) {
  }

  public QueryList GetList(string field, int val,
                         Operation operation) {
    return _GetList(field, val, operation);
  }
  public QueryList GetList(string field, bool val,
                         Operation operation) {
    return _GetList(field, val, operation);
  }
  public QueryList GetList(string field, float val,
                                Operation operation) {
    return _GetList(field, val, operation);
  }
  public QueryList GetList(string field, string val,
                                Operation operation) {
    return _GetList(field, val, operation);
  }
  public QueryList GetList(string field, int val) {
    return _GetList(field, val, Operation.PRIMITIVE_EQUALS);
  }
  public QueryList GetList(string field, bool val) {
    return _GetList(field, val, Operation.OBJECT_EQUALS);
  }
  public QueryList GetList(string field, float val ) {
    return _GetList(field, val, Operation.PRIMITIVE_EQUALS);
  }
  public QueryList GetList(string field, string val) {
    return _GetList(field, val, Operation.OBJECT_EQUALS);
  }
  private QueryList _GetList(string field, object val,
                                       Operation oper) {
    QueryList list = new QueryList();
    IEnumerator myEnumerator = GetEnumerator();
    while (myEnumerator.MoveNext()) {
      object o = myEnumerator.Current;
      Type t = o.GetType();
      FieldInfo info = t.GetField(field, BindingFlags.Public |
          BindingFlags.NonPublic | BindingFlags.Instance );
      object targetval = info.GetValue(o);
      switch ((int)oper) {
        case (int)Operation.OBJECT_EQUALS: if
          (val.Equals(targetval)) list.Add(o); break;
        case (int)Operation.PRIMITIVE_EQUALS : if
          (val == targetval) list.Add(o); break;
        case (int)Operation.GREATER_THAN : if
          (!_IsBool(targetval.GetType()) &&
          _GetDouble(targetval)
          > _GetDouble(val)) list.Add(o); break;
        case (int)Operation.LESS_THAN : if
          (!_IsBool(targetval.GetType()) &&
          _GetDouble(targetval) < _GetDouble(val))list.Add(o);
                                     break;
        case (int)Operation.LESS_THAN_OR_EQUAL : if
          (!_IsBool(targetval.GetType()) &&
          _GetDouble(targetval) <=
          _GetDouble(val)) list.Add(o); break;
        case (int)Operation.GREATER_THAN_OR_EQUAL : if
          (!_IsBool(targetval.GetType()) &&
          _GetDouble(targetval) >=
          _GetDouble(val)) list.Add(o); break;
      }
    }
    return list;
  }

  private bool _IsBool(Type t) {
    return t.Equals(typeof (bool));
  }

  private double _GetDouble(object o) {
    return Double.Parse(o.ToString());
  }

public override string ToString() {
  StringBuilder sbf = new StringBuilder();
  IEnumerator myEnumerator = GetEnumerator();
  while (myEnumerator.MoveNext()) {
    sbf.Append(myEnumerator.Current.ToString()).Append("
");
  }
  return sbf.ToString();
}
}

The class QueryList extends ArrayList. The API for this class contains overloaded methods for searching the collection. The general signature of the calls is as follows:

GetList ( String field, String value)
GetList ( String field, int value)
GetList ( String field, float value)
GetList ( String field, bool value)

Basically, we want to search for those objects in the collection whose field name "field" has the value specified in the value argument. This call can be used to search for simple criteria. The following code gets all persons with the first name of Jack:

GetList ("firstname", "jack")

There is a three-argument call that looks like this:

GetList ( String field, int value, Operation oper)
GetList ( String field, float value, Operation oper)

where Operation is a public enumeration indicating the various operations supported.

So a criterion such as all persons with salary > 60000 would be expressed as follows:

GetList ("salary", 60000, QueryList.Operation.GREATER_THAN);

Note that the GetList method returns a QueryList. This means that we can chain method calls and thereby combine criteria. So to get all males under age 40, we would first find all males and then, within that set, find those under the age 40:

GetList ("male", true).GetList ("age", 40,
QueryList.Operation.LESS_THAN);

This may not be the most efficient way to handle a query. However, the purpose of this exercise is to show how reflection can make it possible to write generic utilities.

Listing 22.7 shows the driver class that uses the QueryList object.

Listing 22.7. Driver Class for Executing the QueryList Utility (C#)
using System;
class QueryListDriver {
  public static void Main(string[] args) {

    QueryList list = new QueryList();
    list.Add( new Person("jack", "daniel",26, 60000, true));
    list.Add( new Person("bud", "weiser",33, 75000, true));
    list.Add( new Person("jack", "monroe",40, 150000, false));
    list.Add( new Person("jack", "kennedy",38, 100000, false));
    list.Add( new Person("ozzy", "ozbourne",50, 200000, true));
    list.Add( new Person("pat", "boone", 70, 40000, true));
    list.Add( new Person("bill", "gates", 45, 900000000,
                                                        true));
    list.Add( new Person("lady", "diana", 36, 80000, false));

    Console.WriteLine("All people with firstname "jack"");
    Console.WriteLine(list.GetList("firstname","jack"));

    Console.WriteLine("All people with salary > 60000 ");
    Console.WriteLine(list.GetList("salary",60000,
             QueryList.Operation.GREATER_THAN));
    Console.WriteLine("All males less than 40 yrs of age ");
    Console.WriteLine(list.GetList("male",true).GetList("age",
                        40, QueryList.Operation.LESS_THAN));
  }
}

The output of Listing 22.7 is as follows:

All people with firstname "jack"
jack,daniel,26,60000,True
jack,monroe,40,150000,False
jack,kennedy,38,100000,False

All people with salary > 60000
bud,weiser,33,75000,True
jack,monroe,40,150000,False
jack,kennedy,38,100000,False
ozzy,ozbourne,50,200000,True
bill,gates,45,9E+08,True
lady,diana,36,80000,False

All males less than 40 yrs of age
jack,daniel,26,60000,True
bud,weiser,33,75000,True

You can use the QueryList class when you are populating an ArrayList with objects from a database and do not want to go back to the database to get a different view of the same list or a subset of the list. For example, if the Person class were mapped to a database row, fetching all the Person objects at once and then using the QueryList class would eliminate the need to run different select queries based on the criteria being used.

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

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