Pluggable Components (Part I) : Brief Overview of Assembly & Modules
Pluggable Components (Part I) : Brief Overview of Assembly & Modules
This is an amazing power that .Net gives you through its reflection technology, which
provides the ground to develop and use the pluggable components during the
execution of application. Before we go on to further details, lets have some brief
review of .Net assemblies, modules, types and how CLR manages them.
At this point, I think the concept of assembly is quite clear to you; but one thing that
might be pondering in your mind is what actually the module mean then? In fact, an
assembly may contain one or more modules. A module is again a physical collection
of types.
You can compile some part of application or component in module (which gets stored
in the file system as .netmodule file) and later combine all the related modules to
make an assembly. So what exactly is the difference between a module and
assembly? An assembly essentially contains something called ‘Manifest’ while a
module does not. Finally, the manifest of an assembly contains the metadata with
following information:
Most of the times, developers do not use multiple modules to pack their types but just
a single module per assembly. Hence, an assembly usually contain types (classes,
interfaces, structures, events) while types contain members (like variables, methods,
properties).
Reflection
The dictionary meaning of the word ‘Reflection’ is ‘to look back to itself’. This is
exactly what is meant by the term reflection in programming world. Reflection is an
ability of application to look into the structure of itself. Using the reflection technology,
we can retrieve the information about the contents of an assembly (constituting
classes and interfaces).
Similarly we can drill down to get the members of these types like fields, methods,
and properties. Not only this, but we can also instantiate these types and invoke the
methods on these. We can even prepare, compile, and load assemblies at runtime!!!
===== Author’s Note: ===== The concept of reflection in .Net (C# & VB.Net) is
similar to that in Java. The standard C++ does not support the reflection but there are
a number of third party libraries available that make reflection possible in C++
Reflection in .Net
The System.Reflection is the root namespace that contains classes to implement the
reflection. The Assembly class is the one which is used to represent the assembly
in .Net environment. A simple program that loads the assembly and prints the names
of the types that it contains is presented below:
using System;
using System.Reflection;
namespace ReflectionTest
{
class Test
{
[STAThread]
static void Main(string[] args)
{
// Load an assembly from file
Assembly myAssembly =
Assembly.LoadFrom("ReflectionTestAssembly.dll");
// Get the types contained in the assembly
and print their names
Type []types = myAssembly.GetTypes();
foreach(Type type in types)
{
Console.WriteLine(type.FullName);
}
}
}
}
Here we have used the static method of the Assembly class ‘LoadFrom()’ which
accepts the complete path and name of the assembly to load in string format. The
method ‘LoadFrom()’ loads an assembly into CLR and returns an instance of type
‘Assembly’ which is an abstraction of the loaded assembly. Using this instance of
type ‘Assembly’, we can do a lot of things.
In the above example, we have called the ‘GetTypes’ method of the ‘Assembly’ class
which gives an array of all the types contained in an assembly. The types are
represented by the ‘System.Type’ class. We then iterated the array and printed the
names of all the types in the assembly on Console. When the above program is run,
it produces the following output on console
ReflectionTestAssembly.MyInterface
ReflectionTestAssembly.MyClass
ReflectionTestAssembly.OurClass
Press any key to continue
Method Description
Creates an instance of the specified type in the assembly and returns its
CreateInstance(string)
object
GetAssembly(Type) static This static method returns the assembly that contains the specified type.
This static method returns the assembly of the method from which the
GetCallingAssembly() static
method containing this code has been called.
This static method returns the assembly that contains this code.For
example, if we call a method in assembly B from assembly A, and the
GetExecuingAssembly() static method in assembly B contains both GetCallingAssembly() and
GetExecutingAssembly() then, GetCallingAssembly() will return
Assembly A while GetExecutingAssembly() will return Assembly B
GetModule(string) Returns the specified module that is part of this assembly
GetModules() Returns an array of all the modules of this assembly
Returns an array of all the assemblies referenced by this assembly. The
GetReferencedAssemblies()
type of array is AssemblyName
Load(AssemblyName) overloaded This static method loads an assembly into CLR provided its
static AssemblyName
LoadFrom(string) static This static method load an assembly into CLR from the specified file
Similarly, some important properties and methods of the Type class are presented in
the following table
Property Description
Assembly Returns the assembly of this type
Namespace Returns the namespace of this type
Attriutes Returns the attributes associated with this type
BaseType Returns the direct base class of the type
FullName Returns the fully qualified name of the type including namespace
IsClass Returns a Boolean value representing whether a type is a class or not
IsInterface Returns a Boolean value representing whether a type is an interface or not
IsEnum Returns a Boolean value representing whether a type is an enumeration or not
IsCOMObject Returns a Boolean value representing whether a type is a COM object or not
IsAbstract Returns a Boolean value representing whether a type is an abstract class or not
Returns a Boolean value representing whether a type is referenced type or not (i.e., passed
IsByRef
by reference)
Returns a Boolean value representing whether a type is value type or not (i.e., passed by
IsValueType
value)
IsPublic Returns a Boolean value representing whether a type is public or not
IsSealed Returns a Boolean value representing whether a type is sealed (can not be inherited) or not
Returns a Boolean value representing whether a type is serializable (can be passed to a
IsSerializable
stream) or not
Method Description
GetInterfaces() Returns all the interfaces implemented or inherited by the type
Returns Boolean representing whether this type is derived from
IsSubclassOf(Type)
the type supplied in the parameter
GetNestedTypes() Returns all the types nested in this type
Returns an object of type ConstructorInfo representing the
GetConstructor(Type[])overloade
constructor of the type which takes the parameter types matching
d the supplied types
Returns an array of ConstructorInfo object representing the
GetConstructors()
constructors of the type.
Returns an array of MemberInfo object representing the members
GetMembers()
(fields, properties, methods) of this type
Returns an array of FieldInfo object representing the fields of this
GetFields()
type
Returns an array of PropertyInfo object representing the properties
GetProperties()
of this type
Returns an array of MethodInfo object representing the methods of
GetMethods()
this type
Returns an array of EventInfo object representing the events of
GetEvents()
this type
Invoke a member (constructor, field, property and method) on the
InvokeMember()
specified object type represented by this instance
Returns a boolean representing whether the current type is derived
IsInstanceOfType()
from the specified type or not
Now as we have seen the few key methods and properties of these classes; lets see
some sample code to perform these tasks.
using System;
using System.Reflection;
namespace ReflectionTest
{
class Test
{
[STAThread]
static void Main(string[] args)
{
// Load an assembly from file
Assembly myAssembly =
Assembly.LoadFrom("ReflectionTestAssembly.dll");
// Get the types contained in the assembly
and print their names
Type []types = myAssembly.GetTypes();
foreach(Type type in types)
{
if(type.IsInterface)
{
Console.WriteLine("\r\n" +
type.FullName + " is an interface");
}
else if(type.IsClass)
{
// Get and print the list of
its parent class and interfaces
Console.WriteLine("\r\n" +
type.FullName +
" is a class whose base class is " +
type.BaseType.FullName);
Console.WriteLine("\t It
implements the following interfaces");
foreach(Type interfaceType in
type.GetInterfaces())
{
Console.WriteLine("\t\t
{0}", interfaceType.FullName);
}
}
}
Console.ReadLine();
}
}
}
Here we got the list of types in the assembly just as we did in the previous example.
We iterated through the types, checked whether it is an interface or a class using the
IsInterface and IsClass properties of the Type class
if(type.IsInterface)
{
...
}
else if(type.IsClass)
{
...
}
If the type is a class, we retrieved the name of its immediate parent class. Since all
classes in .Net are implicitly inherited from the Object class and no class can have
more than one immediate parent class, hence we are sure that the property
BaseType will return exactly one type instance.
Console.WriteLine("\r\n" + type.FullName + " is a class whose
base class is "
+ type.BaseType.FullName);
On the contrary, a class may or may not implement interfaces, so we iterated through
the list of implemented interfaces (if any) using the GetInterfaces() method which
returns an array of Type
The complete source code of the above example can be downloaded from here
using System;
using System.Reflection;
namespace ReflectionTestAssembly
{
public interface MyInterface
{
void Fun(int iParam);
}
public class MyClass : MyInterface
{
private int number;
public readonly double PI = 3.14;
public MyClass()
{
Console.WriteLine("MyClass instantiated");
number = 6;
}
public int Number
{
get { return number; }
set { number = value; }
}
public int GenerateRandom()
{
Random r = new Random();
return r.Next();
}
public void Fun(int iParam)
{
Console.WriteLine("The parameter supplied
is fortunately {0}", iParam);
}
public void SayGreeting()
{
Console.WriteLine("Hello World!");
}
}
}
The following code loads the assembly containing MyClass dynamically and
investigates its members and their types (fields, properties, constructor, methods)
using System;
using System.Reflection;
namespace ReflectionTest
{
class Test
{
[STAThread]
static void Main(string[] args)
{
// Load an assembly from file
Assembly myAssembly =
Assembly.LoadFrom("ReflectionTestAssembly.dll");
// Get the Type object for MyClass
Type myClassType =
myAssembly.GetType("ReflectionTestAssembly.MyClass");
Here we have called the GetMembers() method of the Type instance which returns
an array of type MemberInfo that represents a member of a type
Then for each member, we printed its type using the MemberType property which
returns an enumeration of type MemberTypes. When we executed the above code,
we got the following output.
The member PI is of type Field
The member Fun is of type Method
The member GetHashCode is of type Method
The member Equals is of type Method
The member ToString is of type Method
The member get_Number is of type Method
The member set_Number is of type Method
The member GenerateRandom is of type Method
The member SayGreeting is of type Method
The member GetType is of type Method
The member .ctor is of type Constructor
The member Number is of type Property
Lets have a careful look at the above output. It does not contain private field
‘number’. It also points out to some internals of CLR; the constructor is represented
by .ctor and the properties are expanded to get and set methods. Also note that it
also contains the members inherited from the Object class like GetType(), Equals(),
GetHashCode().
The complete source code of the above sample can be downloaded from here
Consider the first sample, where we have used the FieldInfo object to retrieve
information about the fields of our type.
Note that it only displays the information of public members and not the private
members. Also, not that the data type is not language specific (C# int or VB.Net
Integer) but the MSIL data type (System.Double).
The complete source code of the above sample can be downloaded from here
Similarly, we can use the PropertyInfo and MethodInfo objects to get more
information about properties and methods respectively. Following sample code
demonstrates their use:
The complete source code of the above sample can be downloaded from here
Consider the output generated by the code. It includes all the public or protected
methods which are either declared in the class or derived from the parent class; in
this case the System.Object class (as each class in .Net is derived implicitly from
System.Object class). Also, note that for each property, compiler generates
corresponding get_XXX and set_XXX methods where XXX is the name of the
property.
The MethodInfo class also contains other useful properties like IsAbstract,
IsConstructor, IsFinal, IsPrivate, IsPublic, IsStatic and IsVirtual. Another very
important method of the MethodInfo class is GetParameters() which returns an array
of ParameterInfo using which you can get information about the parameters of a
method. You can use ParameterInfo object just as we have used FieldInfo,
PropertyInfo, and MethodInfo objects.
Here, we used the object of Assembly class to create an instance of MyClass. Note
that the name of class here is given in the form of string. Hence, the compiler does
not know at compile time which object will be created at runtime. This is the reason
why it is another form of Polymorphism. Instead of hard coding the name of class, we
can also take input from user and use the variable name in the CreateInstance()
method. When we run the above code, we got the following output:
MyClass instantiated
Hello World!
The complete source code of the above sample can be downloaded from here
The type (MyClass) considered in the above sample did not contain any
parameterized constructor. Suppose if the constructor of the type MyClass is
The important thing to note here is that we have supplied an array of type
System.Object to the CreateInstance(). The elements in this array will be used as
parameters to call the constructor. Since, here we have only supplied an integer type
array of size 1; therefore, at runtime, the CLR will search for a constructor in type
MyClass which takes 1 integer argument and instantiate the type using this
constructor.
So lets see how we can use this. When we call the InvokeMember(), we supply the
member name in string format, specify member type from
System.Reflection.BindingPolicy enumeration, target object to be used for invocation,
and the array of parameters that might be needed. The method InvokeMember()
returns the value of field, property or result of method to be called. The following
example demonstrates how we can use the InovkeMember() method to invoke fields,
properties and methods.
Console.ReadLine();
}
An important thing to note that when we do not have any parameter to pass to some
method or getting field or property value, we pass a null value in place of parameter
array.
class A
{
public virtual void Fun() { ... }
}
class B : A
{
public override void Fun() { ... }
}
class Test
{
public static void Main()
{
A obj;
int i = new Random().Next(1);
if(i == 0)
obj = new A();
else
obj = new B();
obj.Fun();
}
}
Now neither we nor compiler knows which class’ Fun() method will be called at
runtime, but we do know that the Fun() method will be called. That is, we know the
signature of the method to be called but we don’t know which class’ object will be
used. Now lets see the following code
public class A
{
void Fun() {}
string Do(int p) { }
}
public class Test
{
public static void Main()
{
A myObj = new A();
Type myClassType = myObj.GetType();
string methodName = "";
object parameterArray = null;
int i = new Random().Next(1);
if(i == 0)
{
methodName = "Fun";
}
else
{
methodName = "Do";
parameterArray = new object [] {5};
}
myClassType.InvokeMember(methodName,
BindingFlags.InvokeMethod,
null, myObj, parameterArray);
}
}
Now neither we nor compiler knows which method will be called at runtime. We even
do not know what will be method signature that will be called as opposite to
traditional dynamism
Reflection in .Net – Develop & Use Dynamically
Pluggable Components (Part II)
In the previous part, we investigated how we can get the details of an assembly and
its containing types dynamically using the .Net Reflection technology. We also saw
that we can even instantiates the types dynamically and invoke their members. In this
article, we will go further and see how we can construct types and generate, and
execute MSIL (Microsoft Intermediate Language) code at runtime using what is
called the ‘Reflection Emit’. Later, we will go on to see how we can develop and use
dynamically pluggable components using reflection.
There are basically two methods in .Net to generate dynamic code through your
program. One is to use CodeDom library while other is to use Reflection Emit library.
The System.CodeDom library is used to generate the standard CLS (Common
Language Specification) compliant code that can be emitted in any of .Net
languages. On the other hand, the System.Reflection.Emit library is used to generate
the MSIL (Micrsoft Intermediate Language) code. With this language (compiler)
specific code, you can write any MSIL instruction and can even go for unsafe code.
While CodeDom is relatively easier to use, the reflection emit gives you more power
to directly emit in MSIL code. For the sake of demonstration and relevance to topic,
we will discuss Reflection Emit method in this lesson
Reflection Emit
Dot Net Reflection Emit allows us to construct assemblies, modules, types at runtime
and define code inside these types. We can also instantiate these types, invoke their
members and save the assembly we generated using Reflection Emit in some file.
How does it all work? Well, The System.Reflection.Emit namespace contains classes
to generate assembly, module, types and MSIL code. The general steps followed
are:
Isn’t it all simple, straight forward and to the point? This is the essence of dot net.
http://blogs.msdn.com/joelpob/archive/2004/01/21/61411.aspx
The complete source code is here
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
namespace ReflectionEmitTest
{
class Test
{
[STAThread]
static void Main(string[] args)
{
// create a dynamic assembly and module
AssemblyName assemblyName = new AssemblyName();
assemblyName.Name = "HelloWorld";
AssemblyBuilder assemblyBuilder =
Thread.GetDomain().DefineDynamicAssembly(
assemblyName, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder module;
module =
assemblyBuilder.DefineDynamicModule("HelloWorld.exe");
// bake it
Type helloWorldType = typeBuilder.CreateType();
// run it
helloWorldType.GetMethod("Main").Invoke(null, new
string[] {null});
PEFileKinds.ConsoleApplication);
assemblyBuilder.Save("HelloWorld.exe");
Console.ReadLine();
}
}
}
First of all, we created the name for our new assembly using the AssemblyName
class
AssemblyBuilder assemblyBuilder =
Thread.GetDomain().DefineDynamicAssembly(
assemblyName, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder module =
assemblyBuilder.DefineDynamicModule("HelloWorld.exe");
In this newly created module, we defined a type to hold our Main() method
Here we specified the name of method, its attributes (static and public), return type
and the list of arguments for this method using an array of type System.Type
Now when we have added a method in our type, we need to add some IL code in the
method. We use ILGenerator class to define this IL code
Here we first used EmitWriteLine() method of the ILGenerator class which prints
some text on the console (similar to System.Console.WriteLine() method). Note that
the EmitWriteLine() will not print the ‘hello, world’ on the console when we run the
application. It will simply add the IL code similar to System.Console.WriteLine()
method in our Main() method of newly created assembly which is still in the memory.
Since we do not want to do any other thing, we need to close our method. For this,
we use the Emit() method and specified through OpCodes enumeration that its all
and just return from the method. The Emit() method accepts IL op codes, which you
can provide using OpCodes enumeration.
Then we got the reference of our newly created type (which is still in memory) and
invoked its static Main() method to display ‘hello, world’ on console window
Note that since Main() is a static method, we supplied null in place of target object
(first) parameter of the Invoke() method of the MethodInfo class.
Finally, we set the entry point of our assembly as the Main() method and saved it to
the file
assemblyBuilder.SetEntryPoint(methodbuilder,
PEFileKinds.ConsoleApplication);
assemblyBuilder.Save("HelloWorld.exe");
That’s all it takes to get started with the Reflection Emit technology of Microsoft .Net!!!
Author’s Note: We stop here and do not go into the details of Reflection Emit as it
requires the sound understanding of MSIL and compiler construction. We would,
however, encourage compiler construction students to get into more details of this
topic.
We built the project to get the compiled VBDotNetAssembly.dll file. Now we just
loaded the assembly and instantiate the type ‘VBClass’ and its members as we
earlier used the C# assembly.
using System;
using System.Reflection;
using VBDotNetAssembly;
namespace ReflectionTest
{
class Test
{
[STAThread]
static void Main(string[] args)
{
// Load an assembly from file
Assembly myAssembly =
Assembly.LoadFrom("VBDotNetAssembly.dll");
// Instantiate object
VBClass vbObj = (VBClass) myAssembly.CreateInstance(
"VBDotNetAssembly.VBClass",
false, BindingFlags.Default, null,
null, null, null);
// Get the Type object for this class
Type vbClassType =
myAssembly.GetType("VBDotNetAssembly.VBClass");
// Invoke a parameterless method that returns nothing
vbClassType.InvokeMember("Hello",
BindingFlags.InvokeMethod,
null, vbObj, null);
// Inovoke a method that takes two integer type
parameters and returns
//integer
Hence we can see that dynamic type loading and member invocation through
reflection is not language dependent; we can load and use assemblies built with any
dot net based compiler.
First of all, all the dynamically pluggable components must comply with the common
standard (implement interface or abstract class in OOP). These components can be
added to the application by adding there DLL files. Since, the types in the DLL files
(assembly in .Net) are to be examined, loaded and used dynamically, we need to use
.Net reflection technology for this.
http://www.programmersheaven.com/articles/faraz/reflection/image001.gif
A user selects the DLL file of the task he/she wants to schedule and specify the time
interval to repeat the task. The scheduler then starts the task and repeats it after the
specified time interval.
The first step in designing the application is the standard which all the tasks should
comply with. A task can do whatever it wants, the scheduler should be able to start
the task and repeat it after regular interval. Hence, we defined an interface named
‘Schedule’ in the ‘AbstractSchedule’ assembly (a C# class library project) as:
using System;
namespace AbstractSchedule
{
public interface Schedule
{
void Start();
}
}
The ‘Schedule’ interface only contains one method ‘Start()’ which will be used the
schedule manager start and repeat the task. All the concrete tasks will implement this
method. For example, we have method a task named ‘GreetingTask’ which is a class
library project (assembly). It contains only one class ‘Greeting’ implementing the
‘Schedule’ interface.
using System;
using AbstractSchedule;
namespace GreetingTask
{
public class Greeting : Schedule
{
public void Start()
{
Console.WriteLine("Greeting Task: Hello, World again!");
}
}
}
We developed another task named ‘TimerTask’ which is also a class library project
(assembly). It also contains a class ‘Timer’ implementing the ‘Schedule’ interface.
When invoked it will simply print the current time at Console.
using System;
using AbstractSchedule;
namespace TimerTask
{
public class Timer : Schedule
{
public void Start()
{
Console.WriteLine("Timer Task: Current Time --> {0}",
DateTime.Now.TimeOfDay.ToString());
}
}
}
if(type.GetInterface("AbstractSchedule.Schedule") !=
null)
{
TaskType = type;
{
}
if(taskType == null)
return false;
else
return true;
}
catch(Exception)
{
return false;
}
}
The ValidateTask() accepts the file name with path of the DLL, it attempts to load the
assembly, iterate through all of its types and check if there is any type (class) that
implements the ‘AbstractSchedule.Schedule’ interface. If finds one, it returns true
else it returns false. Also, if there is any exception in doing all this (e.g., the file path
of the dll supplied is not a valid .Net dll), it also returns false.
The next thing, the TaskManager needs to do is to start the task. The task manager
starts each task in a separate thread so that no task can block the application
processing. To manage all these thread, we have an ArrayList to hold all the threads
running
For the repeated execution of the tasks, we have defined a class named
TaskThread. Whenever a task is required to be started, we create an object of this
TaskThread and start a new thread with the execution of TaskThread class Run()
method which repeat the execution of task after given interval of time. The class
TaskThread is defined as follows:
Each TaskThread object contains file name and time interval to repeat the task.
When the task is started, it loads the assembly with the supplied file name, iterate
through its types to get the type implementing the ‘AbstractSchedule.Schedule’
interface. It then instantiate the type and using the ‘Schedule’ interface reference,
execute it repeatedly after regular interval of time. Note that, we expect the interval
supplied by user to be in seconds while the Thread.Sleep() method expects the
interval to be in milliseconds, hence we multiplied the interval value by 1000 to
convert it to the milliseconds.
Finally since each task is being started in different thread, we need to stop all these
threads when the application is to be closed. The StopTasks() method perform this
operation
Now when we have completed the background design, lets design the user interface
form for the application. Make the form look like as:
http://www.programmersheaven.com/articles/faraz/reflection/image002.gif
The ‘Select Task…’ button allows user to select the dll file for the task. The event
handler for this is:
private void btnSelectTask_Click(object sender,
System.EventArgs e)
{
openFileDialog.Filter = "DLL files (*.dll)|*.dll| EXE files
(*.exe)|*.exe" ;
DialogResult res = openFileDialog.ShowDialog();
if(res == DialogResult.OK)
{
txtTask.Text = openFileDialog.FileName;
}
}
It displays the open file dialog box to allow user select the dll file. The openFileDialog
is defined in the form as:
When user press the ‘Add Task’ button, the task file is first validated and then added
to the currently executing tasks.
Finally, since all the tasks are being started in their own threads and the threads are
never ending by themselves, we need to stop these threads when the application is
to be closed. Hence, the StopTasks() method of the TaskManager is called on the
OnClosing() event of the form
When the application is executed and the tasks are added, you can see the output
(repeating hello world and current time) in the Output window. If you can not find the
Output window in your Visual Studio.Net, select View->Other Windows->Output
http://www.programmersheaven.com/articles/faraz/reflection/image003.gif
So, in this lesson we saw how we can use the reflection technology to allow
components to be plugged dynamically in our applications. Reflection is indeed a
very useful technology that allows the code to reason about itself.
Reflection in framework:
Protected Friend Sub CopyState() Implements IUndoableObject.CopyState
Do
' get the list of fields in this type
fields = currentType.GetFields( _
BindingFlags.NonPublic Or _
BindingFlags.Instance Or _
BindingFlags.Public)
If GetType(Csla.Core.IUndoableObject). _
IsAssignableFrom(field.FieldType) Then
' make sure the variable has a value
If Not value Is Nothing Then
' this is a child object, cascade the call
DirectCast(value, IUndoableObject).CopyState()
End If
Else
' this is a normal field, simply trap the value
fieldName = field.DeclaringType.Name & "!" & field.Name
state.Add(fieldName, value)
End If
End If
End If
Next
currentType = currentType.BaseType
End Sub