C# Reflection and Dynamic Method Invocation
Gopalan Suresh Raj

Note
To work with any of these samples, you will need the following:
.........................................Microsoft .NET SDK

The Reflection API allows a C# program to inspect and manipulate itself. It can be used to effectively find all the types in an assembly and/or dynamically invoke methods in an assembly. It can at times even be used to emit Intermediate Language code on the fly so that the generated code can be executed directly.

Reflection is also used to obtain information about a class and its members. Reflection can be used to manipulate other objects on the .NET platform.

The Reflection API uses the System.Reflection namespace, with the Type class to identify the Type of the Class being reflected, and fields of a struct or enum represented by the FieldInfo class, Members of the reflected class represented by the MemberInfo class, Methods of a reflected class represented by the MethodInfo class, and parameters to Methods represented by the ParameterInfo class.

The Activator class's CreateInstance() method is used to dynamically invoke instances on the fly. Dynamic Invocation is very useful in providing a very late-binding architecture, where one component's runtime can be integrated with other component runtimes.

We will illustrate the use of the Reflection API in three different ways:

1. Obtaining Class and Type Information from an Assembly

2. Obtaining Member Information from a Class

3. Dynamically Invoking Methods from Classes in an Assembly

Develop the Test Application

Before we start our forays into C# Reflection and Dynamic Invocation, let us develop our test applications that we'll use to test our Reflection code. Develop an interface called IBase. ImplementationOne and ImplementationTwo are classes that implement the IBase interface and are each compiled into separate assemblies.

1. Develop our Test Base Interface : IBase

IBase.cs
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
/**
* File: IBase.cs
* Article: C# Reflection and Dynamic Method Invocation
* Copyright (c) 2000, Gopalan Suresh Raj. All Rights Reserved.
*/


namespace com.icommware {

/**
  * An enumeration of Color Values
  */

enum ColorEnumeration {
  RED = 1,
  GREEN = 2,
  BLUE = 3
}

/**
  * An Interface with 2 methods
  */

interface IBase {

  string execute (string data);
  double compute (int param1, double param2);
}
}

2. Develop a Test Implementation for the IBase Test Interface : ImplementationOne

ImplementationOne.cs
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
/**
* File: ImplementionOne.cs
* Article: C# Reflection and Dynamic Method Invocation
* Copyright (c) 2000, Gopalan Suresh Raj. All Rights Reserved.
* Compile with: csc /target:library ImplementationOne.cs IBase.cs
*/


using System;

namespace com.icommware {

/**
  * A Class that implements the IBase interface
  */

class ImplementationOne : IBase {

  string remark = "Remark of ImplementationOne";
  static int DELTAFACTOR = 10;

  ImplementationOne () {
   Console.WriteLine ("Invoking ImplementationOne...");
  }

  public string execute (string data) {
   remark = data;
   Console.WriteLine ("ImplementationOne's execute() remark is : {0}", remark);
   return remark;
  }

  public double compute (int param1, double param2) {
   Console.WriteLine ("ImplementationOne's compute() method invoked...");
   return param1*param2*DELTAFACTOR;
  }
}

/**
  * A generic Structure
  */

struct StructOne {
  int x;
  double y;

  double assign () {
   x = 10;
   y = 2.8;
   return x*y;
  }
}
}

3. Compile the Test Application as a Library (DLL) : ImplementationOne.DLL

MS-DOS Command Prompt
H:\gopalan\Reflection>
H:\gopalan\Reflection>
csc /target:library ImplementationOne.cs IBase.cs
Microsoft (R) C# Compiler Version 7.00.8905 [NGWS runtime 2000.14.1812.10]
Copyright (C) Microsoft Corp 2000. All rights reserved.


H:\gopalan\Reflection>
H:\gopalan\Reflection>
csc /target:library ImplementationTwo.cs IBase.cs
Microsoft (R) C# Compiler Version 7.00.8905 [NGWS runtime 2000.14.1812.10]
Copyright (C) Microsoft Corp 2000. All rights reserved.


H:\gopalan\Reflection>

Obtaining All Classes and Their Type Information from an Assembly

   1. Develop an Application that Reflects Types: ReflectTypes

ReflectTypes.cs
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
/**
* File: ReflectTypes.cs
* Article: C# Reflection and Dynamic Method Invocation
* Copyright (c) 2000, Gopalan Suresh Raj. All Rights Reserved.
* Compile with: csc ReflectTypes
* Run as: ReflectTypes <library>
*         eg., ReflectTypes ImplementationOne.dll
*/


using System;
using System.Reflection;

/**
* Develop a class that can Reflect all the Types available in an Assembly
*/

class ReflectTypes {

public static void Main (string[] args) {

  // List all the types in the assembly that is passed in as a parameter
  Assembly assembly = Assembly.LoadFrom (args[0]);

  // Get all Types available in the assembly in an array
  Type[] typeArray = assembly.GetTypes ();

  Console.WriteLine ("The Different Types of Classes Available in {0} are:", args[0]);
  Console.WriteLine ("_____");
  // Walk through each Type and list their Information
  foreach (Type type in typeArray) {
   // Print the Class Name
   Console.WriteLine ("Type Name : {0}", type.FullName);
   // Print the name space
   Console.WriteLine ("Type Namespace : {0}", type.Namespace);
   // Print the Base Class Name
   Console.WriteLine ("Type Base Class : {0}", (type.BaseType != null)?type.BaseType.FullName:"No Base Class Found...");
   Console.WriteLine ("_____");
  }
}
}

2. Compile and Run ReflectTypes (ReflectTypes.EXE) on Our Test Library (ImplementationOne.DLL)

MS-DOS Command Prompt
H:\gopalan\Reflection>
H:\gopalan\Reflection>
csc ReflectTypes.cs
Microsoft (R) C# Compiler Version 7.00.8905 [NGWS runtime 2000.14.1812.10]
Copyright (C) Microsoft Corp 2000. All rights reserved.


H:\gopalan\Reflection>
H:\gopalan\Reflection>
ReflectTypes ImplementationOne.dll
The Different Types of Classes Available in ImplementationOne.dll are:
_____
Type Name : com.icommware.ColorEnumeration
Type Namespace : com.icommware
Type Base Class : System.Enum
_____
Type Name : com.icommware.IBase
Type Namespace : com.icommware
Type Base Class : No Base Class Found...
_____
Type Name : com.icommware.StructOne
Type Namespace : com.icommware
Type Base Class : System.ValueType
_____
Type Name : com.icommware.ImplementationOne
Type Namespace : com.icommware
Type Base Class : System.Object
_____

H:\gopalan\Reflection>

Obtaining Member Information from a Class

   1. Develop an Application that Reflects Methods: ReflectMethods

ReflectMethods.cs
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
/**
* File: ReflectMethods.cs
* Article: C# Reflection and Dynamic Method Invocation
* Copyright (c) 2000, Gopalan Suresh Raj. All Rights Reserved.
* Compile with: csc ReflectMethods
*/


using System;
using System.Reflection;

namespace com.icommware {

/**
  * An enumeration of Account Types
  */

enum AccountEnumeration {
  CHECKING = 1,
  SAVINGS = 2,
}

/**
  * A Class that implements the IBase interface
  */

class ImplementationTwo : IBase {
  string remark = "Remark of ImplementationTwo";
  static int DELTAFACTOR = 100;

  ImplementationTwo () {
   Console.WriteLine ("Invoking ImplementationTwo ...");
  }

  public string execute (string data) {
   remark = data;
   Console.WriteLine ("ImplementationTwo's execute() remark is : {0}", remark);
   return remark;
  }

  public double compute (int param1, double param2) {
   Console.WriteLine ("ImplementationTwo's compute() method invoked...");
   return param1*param2*DELTAFACTOR;
  }
}

/**
  * A generic Structure
  */

struct StructTwo {
  double x;
  int y;

  double assign () {
   x = 8.2;
   y = 10;
   return x*y;
  }
}
}

/**
* Develop a class that can Reflect all the Types available in an Assembly
*/

class ReflectMethods {

public static void Main (string[] args) {

  // retrieve information about AccountEnumeration
  Console.WriteLine ("Names and Values of the com.icommware.AccountEnumeration are:");
  Type type = typeof (com.icommware.AccountEnumeration );

  // Create an instance of AccountEnumeration in Memory
  object accountEnum = Activator.CreateInstance (type);

  // List the names and values available in the AccountEnumeration  enum
  foreach (FieldInfo fieldInfo in type.GetFields (BindingFlags.LookupAll)) {
   object value = fieldInfo.GetValue (accountEnum);
   Console.WriteLine ("{0} = {1}", fieldInfo, value);
  }
  Console.WriteLine ("_____");

  // retrieve information about ImplementationTwo Class
  Console.WriteLine ("The Members of the com.icommware.ImplementationTwo Class are:");
  type = typeof (com.icommware.ImplementationTwo);

  // List the members of the ImplementationTwo Class
  foreach (MemberInfo memberInfo in type.GetFields (BindingFlags.LookupAll)) {
   Console.WriteLine ("{0}", memberInfo);
  }
  Console.WriteLine ("_____");

  // Walk through the methods of the ImplementationTwo Class
  Console.WriteLine ("The Methods of the com.icommware.ImplementationTwo Class are:");
  foreach (MethodInfo methodInfo in type.GetMethods (BindingFlags.LookupAll)) {
   // Print the Method Signature
   Console.WriteLine ("{0}", methodInfo);
   // Walk through the method parameters
   foreach (ParameterInfo parameterInfo in methodInfo.GetParameters ()) {
    // Print the Parameter Type and the Parameter Name
    Console.WriteLine (" Param: {0} {1}", parameterInfo.ParameterType, parameterInfo.Name);
   }
   Console.WriteLine ("_____");
  }


  // retrieve information about StructTwo Class
  Console.WriteLine ("The Members of the com.icommware.StructTwo Class are:");
  type = typeof (com.icommware.StructTwo);

  // List the members of the StructTwo Class
  foreach (MemberInfo memberInfo in type.GetFields (BindingFlags.LookupAll)) {
   Console.WriteLine ("{0}", memberInfo);
  }
  Console.WriteLine ("_____");
  // Walk through the methods of the StructTwo Class
  Console.WriteLine ("The Methods of the com.icommware.StructTwo Class are:");
  foreach (MethodInfo methodInfo in type.GetMethods (BindingFlags.LookupAll)) {
   // Print the Method Signature
   Console.WriteLine ("{0}", methodInfo);
   // Walk through the method parameters
   foreach (ParameterInfo parameterInfo in methodInfo.GetParameters ()) {
    // Print the Parameter Type and the Parameter Name
    Console.WriteLine (" Param: {0} {1}", parameterInfo.ParameterType, parameterInfo.Name);
   }
   Console.WriteLine ("_____");
  }
}
}

2. Compile and Run ReflectMethods (ReflectMethods.EXE)

MS-DOS Command Prompt
H:\gopalan\Reflection>
H:\gopalan\Reflection>csc ReflectMethods.cs IBase.cs
Microsoft (R) C# Compiler Version 7.00.8905 [NGWS runtime 2000.14.1812.10]
Copyright (C) Microsoft Corp 2000. All rights reserved.


H:\gopalan\Reflection>
ReflectMethods
Names and Values of the com.icommware.AccountEnumeration are:
Int32 value__ = 0
com.icommware.AccountEnumeration CHECKING = 1
com.icommware.AccountEnumeration SAVINGS = 2
_____
The Members of the com.icommware.ImplementationTwo Class are:
System.String remark
Int32 DELTAFACTOR
_____
The Methods of the com.icommware.ImplementationTwo Class are:
Double compute (Int32, Double)
Param: Int32 param1
Param: Double param2
_____
System.String execute (System.String)
Param: System.String data
_____
Void Finalize ()
_____
Int32 GetHashCode ()
_____
Boolean Equals (System.Object)
Param: System.Object obj
_____
System.String ToString ()
_____
System.Type GetType ()
_____
System.Object MemberwiseClone ()
_____
The Members of the com.icommware.StructTwo Class are:
Double x
Int32 y
_____
The Methods of the com.icommware.StructTwo Class are:
Void Finalize ()
_____
Int32 GetHashCode ()
_____
Boolean Equals (System.Object)
Param: System.Object obj
_____
System.String ToString ()
_____
Double assign ()
_____
System.Type GetType ()
_____
System.Object MemberwiseClone ()
_____

H:\gopalan\Reflection>

Dynamically invoking methods from a class in an Assembly

We use Reflection to open all the Assemblies on the command line, search for Classes that implement the com.icommware.IBase interface, create an instance of that class and invoke the compute() method on the assembly.

1. Develop an Application that dynamically invokes methods from an Assembly

DynamicInvocation.cs
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
/**
* File: DynamicInvocation.cs
* Article: C# Reflection and Dynamic Method Invocation
* Copyright (c) 2000, Gopalan Suresh Raj. All Rights Reserved.
* Compile with: csc DynamicInvocation.cs
* Run As: DynamicInvocation <library | Application...>
*         eg., DynamicInvocation ImplementationOne.DLL ReflectMethods.EXE
*/


using System;
using System.Reflection;
using com.icommware;

class DynamicInvocation {

  public static void invokeProcess (string assemblyName) {
   Console.WriteLine ("Loading {0} into memory...", assemblyName);
   Assembly assembly = Assembly.LoadFrom (assemblyName);
  
   // Walk through each type in the assembly
   foreach (Type type in assembly.GetTypes ()) {
    // Pick up a class
    if (type.IsClass == true) {
     Console.WriteLine ("...Found Class : {0}", type.FullName);
    
     // If it does not implement the IBase Interface, skip it
     if (type.GetInterface ("com.icommware.IBase") == null) {
      continue;
     }
    
     // If however, it does implement the IBase Interface,
     // create an instance of the object
     object ibaseObject = Activator.CreateInstance (type);
    
     // Create the parameter list
     object[] arguments = new object [] {10, 17.11};
     object result;
     // Dynamically Invoke the Object
     Console.WriteLine ("......Dynamically Invoking compute() on {0} Class", type.FullName);
     result = type.InvokeMember ("compute",
                                 BindingFlags.Default | BindingFlags.InvokeMethod,
                                 null,
                                 ibaseObject,
                                 arguments);

     Console.WriteLine ("......Result is: {0}", result);    
    }
   }
  }

  public static void Main (string[] args) {
   foreach (string argument in args) {
    invokeProcess (argument);
   }
  }

}

2. Compile and Run DynamicInvocation (DynamicInvocation.EXE)

MS-DOS Command Prompt
H:\gopalan\Reflection>
H:\gopalan\Reflection>csc DynamicInvocation.cs IBase.cs
Microsoft (R) C# Compiler Version 7.00.8905 [NGWS runtime 2000.14.1812.10]
Copyright (C) Microsoft Corp 2000. All rights reserved.


H:\gopalan\Reflection>
DynamicInvocation ImplementationOne.DLL ReflectMethods.EXE
Loading ImplementationOne.DLL into memory...
...Found Class : com.icommware.ImplementationOne
Invoking ImplementationOne...
......Dynamically Invoking compute() on com.icommware.ImplementationOne Class
ImplementationOne's compute() method invoked...
......Result is: 1711
Loading ReflectMethods.EXE into memory...
...Found Class : com.icommware.ImplementationTwo
Invoking ImplementationTwo ...
......Dynamically Invoking compute() on com.icommware.ImplementationTwo Class
ImplementationTwo's compute() method invoked...
......Result is: 17110
...Found Class : ReflectMethods

H:\gopalan\Reflection>

H:\gopalan\Reflection>

 

Download the entire source code as a zip file.

 

click here to go to
My Advanced C#/.NET Tutorial Page...

About the Author...
Gopalan Suresh Raj is a Software Architect, Developer and an active Author. He is contributing author to a couple of books "Enterprise Java Computing-Applications and Architecture" and "The Awesome Power of JavaBeans". His expertise spans enterprise component architectures and distributed object computing. Visit him at his Web Cornucopia© site (http://www.execpc.com/~gopalan) or mail him at gopalan@execpc.com.

 


Go to the Component Engineering Cornucopia page

This site was developed and is maintained by Gopalan Suresh Raj

This page has been visited times since October 19, 2000.

Last Updated : Oct 19, '00

If you have any questions, comments, or problems regarding this site, please write to me I would love to hear from you.


Copyright (c) 1997-2000, Gopalan Suresh Raj - All rights reserved. Terms of use.

All products and companies mentioned at this site are trademarks of their respective owners.