Article

This is in continuation to Reflection in .NET - Part 3

ReflectionPermission

If ReflectionPermission is not granted to the code, it can access only the public members of the loaded assemblies. The code having the appropriate ReflectionPermission has access to non-public members of any loaded Type. This includes access to Module and Assembly.

The caller needs to have ReflectionPermission and then only it can reflect on private fields, methods, constructors, and properties. For example, before FieldInfo.SetValue() sets the value of an underlying field reflected by a FieldInfo instance, it ensures whether the user has appropriate ReflectionPermission.

If the code is fully trusted, access restrictions are ignored. A fully trusted code is allowed to access and invoke the private methods, constructors, properties, and fields through reflection. However, if the code is from an untrusted source, ReflectionPermission makes it possible to enumerate the types, retrieve type and member information, and invoke methods that would otherwise be inaccessible.

Since ReflectionPermission allows access to class members and information that is not intended for public access, it is advisable that ReflectionPermission should not be granted to the Internet code. It is granted only to trusted code.

Assembly class

It is the principal class in the System.Reflection namespace. For the purpose of reflection, .NET has provided the Assembly class that encapsulates the information about a .NET assembly. In other words, its instance represents a .NET assembly.

You can load an assembly at runtime by making a call to the Assembly.Load() static method. You can pass to this method an AssemblyName object that encapsulates information about the assembly's unique identity such as its name, version number etc. The Load() is an overloaded method that also accepts a full name of an assembly, also known as the display name.

Use LoadFrom() method if you want to obtain an Assembly object corresponding to the file lying on a hard drive. This method accepts the file name and path of the assembly and dynamically loads it and returns the corresponding Assembly object.

You can call the GetExecutingAssembly() method if you want to obtain an Assembly object that represents the currently executing assembly.

Once you have an Assembly object in memory, you can use its properties and methods to query for information in the assembly. It has the properties such as FullName, Entry Point, Location. EntryPoint returns the entry point of the assembly. Location returns the physical name and location of the assembly. FullName returns the full name of the assembly, also known as the display name. FullName includes information about the version number, culture, and public key token.

Use GetTypes() if you want to retrieve all the Types defined in an assembly. It returns an array of Type objects. Use GetType() if you want to retrieve a Type object that represents a specified type.

Use GetModules() if you want to obtain all the modules listed in an assembly manifest. It returns an array of Module objects. GetModule() returns the specified module from the assembly.

Use Module.GetType() if you want to obtain a type from a specific module. If you want to obtain a type from an assembly, irrespective of which module it is in, you need to make a call to Assembly.GetType() method.

Loading an assembly given its full name

Assembly asm = null;
AssemblyName asmName = new AssemblyName();
asmName.Name = "MyAssembly";
asmName.Version = new Version("1.0.0.2005");
try {
    asm = Assembly.Load(asmName);
    Console.WriteLine ("Assembly successfully loaded.");
}
catch (Exception e) {
    Console.WriteLine( e.Message );
}

Finding Types in a running program

Using the Reflection API, a running program can obtain the information about itself, for e.g. it can find all the types in the currently executing assembly and then it can retrieve all the methods in each type.

using System;
using System.Reflection;
public class Square {
    public int side;
    public int CalculateArea() {
        return side*side;
    }
}

public class AssemblyReflectionDemo1 {
    public static void Main() {
        //Obtain the assembly the current code is running from
        Assembly asm = Assembly.GetExecutingAssembly(); 

        Console.WriteLine ("Assembly Full Name = {0}\n", asm.FullName);
        Console.WriteLine ("Assembly Entry Point = {0}\n", asm.EntryPoint);
        Console.WriteLine ("Assembly Location = {0}", asm.Location);

        //Retrieve all the types in the assembly and iterate through the array of Type objects
        Type[] types = asm.GetTypes();
        foreach (Type type in types) {
            Console.WriteLine ("\nType: {0}", type.Name);

            //Retrieve all the methods in the type
            MethodInfo[] methods = type.GetMethods();
            foreach (MethodInfo method in methods)
                Console.WriteLine("  {0}", method.ToString());
        }
    }
}

Output

//Since it is a private assembly, the value of PublicKeyToken is null.

Assembly Full Name = MyAssembly, Version=…, Culture=neutral, PublicKeyToken=null
Assembly Entry Point = Void Main()
Assembly Location = C:\...\MyAssembly.exe
Type: Square
    Int32 GetHashCode()
    Boolean Equals(System.Object)
    System.String ToString()
    Int32 CalculateArea()
    System.Type GetType()
Type: AssemblyReflectionDemo1
    Int32 GetHashCode()
    Boolean Equals(System.Object)
    System.String ToString()
    Void Main()
    System.Type GetType()

Binding Flags enumeration

It is a set of flags that controls the way in which the search for the members and types is conducted by reflection. It has the values like

a. Public: indicates that the public members are to be included in the search.

b. NonPublic: indicates that the private, protected, and internal members are to be included in the search.

c. Instance: indicates that the instance members should be considered.

d. Static: indicates that the static members should be considered.

e. DeclaredOnly: indicates that the search should not include any inherited members. It should include only those members that are declared at the type's hierarchy level.

The BindingFlags enumeration is used in the Type methods such as GetFields(), GetField(), GetMethods(), GetMethod(), FindMembers(), GetMembers(), GetConstructors(), GetConstructor(). Foe example, an overloaded Type.GetMethods(BindingFlags) looks for the methods of a given type using the specified binding constraints and returns an array of the MethodInfo object where each object represents a method that matches the specified binding constraints.

Get the public, instance methods of the ArrayList class whose names begin with 'To'. The program should return only those methods that are declared for ArrayList i.e. do not include the inherited methods such as Object.ToString().

using System;
using System.Reflection;

public class BindingFlagsReflectionDemo {
    public static void Main() {
        Assembly asm = null;
        try {

            //ArrayList class resides in mscorlib.dll
            asm = Assembly.Load ("mscorlib.dll");
            Type type = asm.GetType ("System.Collections.ArrayList");

            MemberInfo[] members =  type.FindMembers(MemberTypes.Method, 
                                    BindingFlags.Public | BindingFlags.Instance | 
                                    BindingFlags.DeclaredOnly, Type.FilterName, "To*");

            foreach (MemberInfo member in members)
                Console.WriteLine("{0} {1}", member, member.MemberType);
        }
        catch (Exception e) {
            Console.WriteLine( e.Message );
        }
    }
}

Output
System.Array ToArray(System.Type) Method
System.Object[] ToArray() Method

For Part 5, click this link: Reflection in .NET - Part 5