Wikipedia said:
System.Reflection
Provides an object view of types, methods, and fields. You have "the ability to dynamically create and invoke types". It exposes the API to access the Reflective programming capabilities of CLR.
Provides an object view of types, methods, and fields. You have "the ability to dynamically create and invoke types". It exposes the API to access the Reflective programming capabilities of CLR.
Reflecting on an assembly and its types
To demonstrate this, let's setup a hypothetical situation in which we have an application, and a .NET DLL unreferenced by our application whose types we need to access at runtime. The DLL will be called MyDLL.dll, and the application will be called MyApp.exe. How would we view the types contained inside MyDLL from MyApp at runtime when MyDLL isn't referenced by MyApp? The System.Runtime.Assembly class can be used to access MyDLL in the following manner
System.Reflection.Assembly myDllAssembly = System.Reflection.Assembly.LoadFile("%MyDLLPath%\\MyDLL.dll");
The myDllAssembly object can now be used to access the types contained inside MyDLL. To access a type contained inside MyDLL, System.Reflection.Assembly possesses a method called GetType() which can return a System.Type that can be used to access all the members of the type we want to retrieve from inside MyDLL. Note that the System.Reflection.Assembly.GetType() method is not to be confused with the GetType() method possessed by all objects; they are related, but quite different and we will discuss the other GetType() method later. Back to our example, let's say there is a type inside MyDLL called MyDLLForm which inherits from System.Windows.Forms.Form and is contained in the namespace MyDLLNamespace. To obtain the System.Type of this, we could do the following
System.Reflection.Assembly myDllAssembly = System.Reflection.Assembly.LoadFile("%MyDLLPath%\\MyDLL.dll");
System.Type MyDLLFormType = myDllAssembly.GetType("MyDLLNamespace.MyDLLForm");
MyDLLFormType now holds the System.Type of MyDLLForm. We can now access all the members and contained types inside MyDLLForm from MyDLLFormType. However, using this GetType() method will not create an instance of MyDLLForm. To access a type contained inside MyDLL and create an instance of it, System.Reflection.Assembly possesses another method called CreateInstance(). Say we wanted to create an instance of MyDLLForm, we could use something like this
System.Reflection.Assembly myDllAssembly = System.Reflection.Assembly.LoadFile("%MyDLLPath%\\MyDLL.dll");
Form MyDLLFormInstance = (Form)myDllAssembly.CreateInstance("MyDLLNamespace.MyDLLForm");
MyDLLFormInstance now holds an instance of MyDLLForm (remember that MyDLLForm inherits from Form). To create an instance of MyDLLForm, that method will invoke MyDLLForm's constructor. By way of that overload, CreateInstance is expecting a constructor that takes no arguments, as we only passed it the type name we want to create an instance of. However, lets say there is a constructor we want to use to create an instance of MyDLLForm that takes two arguments, a string and an int. To do that, and for example to pass it a string of "Hi" and an integer value of 113 (one of my favorite numbers), we could use this
System.Reflection.Assembly myDllAssembly = System.Reflection.Assembly.LoadFile("%MyDLLPath%\\MyDLL.dll");
//the arguments we will pass
object[] argstopass = new object[] { (object)"Hi", (object)113 };
Form MyDLLFormInstance = (Form)myDllAssembly.CreateInstance("MyDLLNamespace.MyDLLForm",
false, //do not ignore the case
BindingFlags.CreateInstance, //specifies we want to call a ctor method
null, //a null binder specifies the default binder will be used (works in most cases)
argstopass, //the arguments (based on the arguments, CreateInstance() will decide which ctor to invoke)
null, //CultureInfo is null so we will use the culture info from the current thread
null //no activation attributes
);
Read the comments, they should tell you what's happening pretty good.
Reflecting on a single type
Fields
The CreateInstance() method can easily create an instanced object of any type in an assembly we've loaded in a System.Reflection.Assembly, however, you can see that in the example above MyDLLFormInstance is of type System.Windows.Forms.Form, which is the inherited type of MyDLLForm. However, say there are custom members contained inside MyDLLForm that we need to access. MyDLLFormInstance is of type System.Windows.Forms.Form, so any members we have created inside MyDLLForm we cannot access directly by MyDLLFormInstance. This is where that other GetType() methods that all objects possess comes in handy. Lets say for an example, there is a public string variable contained inside MyDLLForm called StringVariable. To retrieve the value of that variable from MyDLLFormInstance, the following code can be used
string StringVariableValue = (String)MyDLLFormInstance
.GetType() //Get the type of MyDLLForm
.GetField("StringVariable") //Get a System.Reflection.FieldInfo object representing StringVariable
.GetValue(MyDLLFormInstance); //Get the actual value of StringVariable
That will assign StringVariableValue to the value of StringValue contained in MyDLLFormInstance. The GetType() method is used to get the System.Type of MyDLLFormInstance. It will return a type that represents MyDLLForm, because even though MyDLLFormInstance is declared as a Form, it's actual value is of MyDLLForm. We can then use the GetField() method of that System.Type to return the value of the StringVariable field in MyDLLFormInstance.
Say, however, we want to set StringVariable in that same instance instead of retrieving its value. We can use almost the same method, except instead of calling the GetValue() method of the FieldInfo that represents StringValue, we can use the SetValue() method like so
MyDLLFormInstance
.GetType() //Get the type of MyDLLForm
.GetField("StringVariable") //Get a System.Reflection.FieldInfo object representing StringVariable
.SetValue(MyDLLFormInstance, //the object whose StringVariable field we want to set (MyDLLFormInstance)
(object)"This string will be the new value of StringVariable" //the new value of StringVariable
);
That will then set the StringVariable field in MyDLLFormInstance.
Properties
But what if there is a property in MyDLLForm that we want to retrieve in MyDLLFormInstance, called StringProperty, for example. We can use this method to get the property's value
MyDLLFormInstance
.GetType() //Get the type of MyDLLForm
.GetProperty("StringProperty") //Gets a System.Reflection.PropertyInfo object representing StringProperty
.GetValue(MyDLLFormInstance, null); //Gets the property's value
Now, if we wanted to set the value of the same property (if the property isn't read-only)
MyDLLFormInstance
.GetType() //Get the type of MyDLLForm
.GetProperty("StringProperty") //Gets a System.Reflection.PropertyInfo object representing StringProperty
.SetValue(MyDLLFormInstance, (object)"This will be the new value of StringProperty", null); //Sets the value of StringProperty
Methods
Now you know how to modify and retrieve the value of public fields and properties contained inside assemblies loaded in an System.Reflection.Assembly object. However, probably the most important is knowing how to invoke methods. So, using the same MyDLL scenario, lets say there is a method in MyDLLForm that returns void and takes no arguments called SomeMethod. This will be quite easy to invoke, as there is no arguments to pass, and we will not need to retrieve the value. To invoke that method, we can easily use, on the same MyDLLFormInstance object
MyDLLFormInstance
.GetType() //Get the type of MyDLLForm
.GetMethod("SomeMethod") //Gets a System.Reflection.MethodInfo object representing SomeMethod
.Invoke(MyDLLFormInstance, null); //here we invoke SomeMethod. The arguments list is null because it takes no arguments
Lets make this situation a bit more complex. Lets say SomeMethod takes 2 arguments, a string and an int. Lets use the same two example values from our CreateInstance example; "Hi" as the string and 113 and the integer. Remember, SomeMethod takes arguments, but it still returns void, so we don't need to retrieve the value. To invoke SomeMethod this time, we could use
//This is the arguments list. "Hi" is the string and 113 is the int
object[] argstopass = new object[] { (object)"Hi", (object)113 };
MyDLLFormInstance
.GetType() //Get the type of MyDLLForm
.GetMethod("SomeMethod") //Gets a System.Reflection.MethodInfo object representing SomeMethod
.Invoke(MyDLLFormInstance, argstopass); //here we invoke SimpleMethod. We also pass ArgsToPass as the argument list
Now, let's make this as complicated as we can get it. Lets say that SomeMethod takes those same arguments, and returns a value of string which you need to retrieve when you invoke SomeMethod. This is really quite easy, because the Invoke() method we used in the past two examples returns a type of object, which will hold the value returned by the method it invoked. So, to get the string returned by SomeMethod, we can use
//This is the arguments list. "Hi" is the string and 113 is the int
object[] argstopass = new object[] { (object)"Hi", (object)113 };
string ReturnValue = (string)MyDLLFormInstance
.GetType() //Get the type of MyDLLForm
.GetMethod("SomeMethod") //Gets a System.Reflection.MethodInfo object representing Some
.Invoke(MyDLLFormInstance, argstopass) //here we invoke SomeMethod. We also pass ArgsToPass as the argument list
In that example, ReturnValue will hold the value returned by SomeMethod when we invoked it.
Events
Now, what about events? Lets say we have an event in MyDLLForm called SomeEvent that we want to access in MyDLLFormInstance. To obtain a System.Reflection.EventInfo object representing that event, simply use
MyDLLFormInstance
.GetType() //Get the type of MyDLLForm
.GetEvent("SomeEvent"); //Gets a System.Reflection.EventInfo object representing SomeEvent
Now, lets pretend that event uses a simple EventHandler delegate. To add an event handler for that event, use
MyDLLFormInstance
.GetType() //Get the type of MyDLLForm
.GetEvent("SomeEvent") //Gets a System.Reflection.EventInfo object representing SomeEvent
.AddEventHandler(MyDLLFormInstance, new EventHandler(SomeEventHandler)); //Adds SomeEventHandler as an event handler for SomeEvent
//------------------------------------------------------------------------------------------
//This method will be the event handler for SomeEvent in MyDLLFormInstance
public void SomeEventHandler(object sender, EventArgs e)
{
}
And to remove that same event handler
MyDLLFormInstance
.GetType()
.GetEvent("SomeEvent") //Gets a System.Reflection.EventInfo object representing SomeEvent
.RemoveEventHandler(MyDLLFormInstance, new EventHandler(SomeEventHandler)); //Removes SomeEventHandler as an event handler for SomeEvent
//------------------------------------------------------------------------------------------
//This method will be removed as the event handler for SomeEvent in MyDLLFormInstance
public void SomeEventHandler(object sender, EventArgs e)
{
}
Nested Types
What if there are types contained inside a type in an assembly? That is quite easy. Going along with our example, let's say MyDLLForm contains a nested class called MyDLLFormNestedType. To access that, use
myDllAssembly
.GetType("MyDLLForm") //Gets a type representing MyDLLForm
.GetNestedType("MyDLLFormNestedType") //Gets a type representing MyDLLFormNestedType, which is nested inside MyDLLForm
Notice we are not accessing MyDLLFormNestedType through MyDLLFormInstance, but instead we are accessing the assembly with MyDllAssembly, and then retrieving the System.Type of MyDLLForm, and from that retrieving the System.Type of the nested type MyDLLFormNestedType. You can then interact with that nested type the same as you can interact with the type containing it (creating instances of it, accessing the members contained in it, etc).
Though this example we used throughout this tutorial was pertaining to loading a class inheriting from form contained inside a DLL, don't for a second think that i'm implying that you can only access classes contained inside an assembly. You can access any type, class, struct, interface, or anything. Not only can System.Reflection be used to load unreferenced assemblies, as demonstrated in this tutorial, but it can be used to make powerful decompilers and code analyzers. .NET Reflector, a powerful .NET decompiler, would not exist if it wasn't for the System.Reflection namespace and the reflective capabilities of the CLR.





MultiQuote




|