8.3. Modifying the Retrieval through BindingFlags

As it happens, the string class has five properties, only two of which are public. By default, the Get methods retrieve only public instance members—both inherited members and those declared in the class. We can use a BindingFlags enum object to override the default retrieval policy to retrieve both static and nonpublic members or to suppress retrieval of inherited members.

The BindingFlags enumerators provide instructions to the retrieval algorithm as to what members to consider. The default pair of BindingFlags enumerators consists of Public and Instance. If we want to retrieve the nonpublic members as well, we pass in the NonPublic enumerator.[1] The following, however, does not work:

[1] Provided that the ReflectionPermission security code permits access to nonpublic members. If it does not, an exception of type SecurityException is thrown.

PropertyInfo[] parray = t.GetProperties(BindingFlags.NonPublic);

This invocation always returns null, failing to retrieve anything. For this to work, we must also tell the algorithm which members to consider. To find all the nonpublic instance members, we apply the bitwise OR operator on the values:

BindingFlags f= BindingFlags.NonPublic | BindingFlags.Instance;
PropertyInfo[] parray = t.GetProperties( myFlags );

To find all the static and instance properties—both public and nonpublic—we write the following:

// OK: retrieve all static and instance members
// that are public and nonpublic

BindingFlags bitmap = BindingFlags.Public|
                              BindingFlags.NonPublic;

// consider all static members
bitmap |= BindingFlags.Static;

// consider all instance members
bitmap |= BindingFlags.Instance;

PropertyInfo [] parray = t.GetProperties( bitmap );

The LookupAll enumerator provides a shorthand notation for the retrieval of all public and nonpublic static and instance members. The following call is the equivalent of the one we just made:

// OK: this is a shorthand notation:
// it also retrieves all public
// and nonpublic static and instance members

PropertyInfo[] parray = t.GetProperties(BindingFlags.LookupAll);

Generally we apply bitwise OR on the individual enumerators only when we wish to fine-tune our retrieval between the default of public instance members only and the all-inclusive retrieval of LookupAll.

The NonPublic and LookupAll values retrieve protected members of the base class. They do not retrieve the base-class private members.

Let's query the String class regarding its data members both with and without the BindingFlags argument.

The FieldInfo class holds information about a data member. By default, GetFields() is not likely to retrieve most class members; typically we define data members as private. For example, here is the result of invoking GetFields() on a string:

number of public string fields: 1

That's surprising. We would expect more than one field to be associated with the String class. When we invoke GetFields() with the LookupAll value as its argument:

fi = t.GetFields(BindingFlags.LookupAll);
Console.WriteLine( "total number of string fields: {0}",
                    fi.Length );

our retrieval is considerably more successful:

total number of string fields: 13

Some of the properties associated with the FieldInfo class include Name, IsPublic, IsPrivate, and IsStatic. (For some reason there is currently no property for protected access.) The following foreach loop reads each of these members:

foreach ( FieldInfo f in fi )
{
   Console.Write( "	{0} :: ", f.Name );
   Console.Write( "{0} ",
          f.IsPublic
                 ? "public"
                 : f.IsPrivate
                 ? "private" : "property?" );

   Console.Write( "{0} ", f.IsStatic ? "static" : "" );
}

This loop generates the following output:

The 13 fields are as follows:
      m_arrayLength :: private
      m_stringLength :: private
      m_firstChar :: private
      Empty :: public static
      WhitespaceChars :: private static
      MASK_LENGTH :: private static
      MASK_CHARS :: private static
      HAS_NO_HIGH_CHARS :: private static
      HAS_HIGH_CHARS :: private static
      HIGH_CHARS_UNDETERMINED :: private static
      TrimHead :: private static
      TrimTail :: private static
      TrimBoth :: private static

Twenty enumerator values are defined within BindingFlags. Two others of interest are DeclaredOnly, which limits the retrieval to members defined in the class (no inherited members are retrieved), and IgnoreCase, which we optionally pass when retrieving a member by name. Each Get method supports an overloaded second instance, taking a second argument of type BindingFlags.

The GetConstructors() method retrieves public instance constructors only. To retrieve the static constructor as well, we must explicitly request the static instance, as follows:

// retrieves public constructors and
// the static constructor, if present
BindingFlags f = BindingFlags.Instance;
f |= BingingFlags.Static;
f |= BindingFlags.Public;

ConstructorInfo[] ci = t.GetConstructors(f);

To retrieve the nonpublic constructors as well, either we explicitly add the Private enumerator through a bitwise OR or we can use LookupAll. Because base-class constructors are not inherited, they are not retrieved.

How do we select an individual constructor? We can't just give its name; all constructors share the same name. What distinguishes a constructor is its signature. That's what we must pass in. To retrieve an individual constructor, we create and pass in an array of Type objects representing the type of each parameter of the constructor. The following code shows two examples. The first retrieves a constructor that takes no arguments, or null if this constructor is not present. The second retrieves a constructor that takes a string first argument and an int second argument:

// first we define the two arrays
static Type [] nullSignature = new Type[0];

static Type [] stringIntSignature = new Type[]{
            Type.GetType("System.String", true ),
            Type.GetType("System.Int32" )
};
ConstructorInfo ctor = t.GetConstructor( nullSignature );
if ( ctor != null ){ ... }

ctor = t.GetConstructor( stringIntSignature );
if ( ctor != null ){ ... }

This is also true of overloaded functions. We cannot distinguish between two overloaded instances of a function named Print() by the name alone. Rather we must pass in a second argument identifying the signature of the instance we wish to retrieve. This second argument is an array of Type objects representing each parameter in turn—for example,

MethodInfo mi = t.GetMethod( "Print", stringIntSignature );

To get all the class methods (but not constructors), we use GetMethods(). This method returns an array of MethodInfo objects. If the type has no methods, an empty array is returned.

So far we have retrieved members of only a certain kind—all properties, for example, or all constructors. If we want to retrieve every member unconditionally, we use the GetMembers() method. By default, GetMembers() returns only public static and instance members. We can override the default, of course, by passing in a second argument of type BindingFlags.

There is also a GetMember(string) method. If a member with the specified name is found, GetMember() returns a MemberInfo array rather than a single object. The reason is that a method's name may be overloaded. If no member with the name is found, null is returned rather than an empty array.

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

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