Preface
This series of articles will explain Reflection in .NET in detail, then take a deep dive into its various aspects and also cover the various classes in the System.Reflection namespace. On our path to understand Reflection, we will be covering many sample examples (demo programs that I have created) to explain the concept practically. I will be including various techniques using examples (demo programs) that the programmers can use in their applications when implementing Reflection.
Introduction
An Assembly is the minimum unit of deployment. You cannot deploy anything less than an Assembly. For the CLR, a type does not exist outside the context of an Assembly. Assemblies contain four elements (the Assembly manifest, type metadata, MSIL and resources.). Each Assembly contains a collection of data that describes how the elements in the Assembly relate to each other. For more information on Assemblies (see the bottom section, References). In our custom .NET applications, when using reflection the Type metadata information will be used.
Reflection
Reflection in .NET allows us to programatically load Assemblies and obtain information about the types (classes, interface and value types) defined in the Assemblies.
Reflection can also be used to dynamically create an instance of a type, bind the type to an existing object, or get the type information from an existing object. The .NET Framework includes System.Reflection, System.Type and they together form the reflection API, this API can be used to programatically obtain information about the loaded Assembly.
Reflection also allows you to perform late binding, wherein you load the Assembly, access the type, create an instance of the type, invoke the methods of the type (using the method name), all at Runtime.
Let's start with our first Demo.
Using Reflection, for Loading a .NET Framework Assembly and displaying the types
The following is the image of the running code, console application (see attachments for the complete code). In the following procedure, I will walk you through each line of the code.
Figure 1: Running code console application
In this console application example, we are loading the .NET Assembly (System.Data.dll) and looping through the types contained in this Assembly at runtime using reflection.
First you specify the reflection namespace using the using directive.
Inside the Main method (entry point for most types of C# applications) define a string variable to specify the exact location (path) of the Assembly (you can specify any other .NET Assembly name with the complete path).
- string assemblyPath = @"C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\System.Data.dll";
On the next line, the preceding specified path would be used to load the Assembly using LoadFrom(), that accepts a string parameter (in other words the path of the Assembly).
- Assembly assembly = Assembly.LoadFrom(assemblyPath);
On the next line we display the full name (fully qualified name of the Assembly with namespace information, name, version, culture and public key) of the Assembly that's loaded.
-
- Console.WriteLine("Assembly Full Name : {0}", assembly.FullName);
In the next line using the GetTypes() method we will get all the types from the loaded Assembly in aType[].
-
- Type[] assemblyTypes = assembly.GetTypes();
We will then use foreach to loop through the types and display the FullName property of each type on the console screen.
- foreach (Type t in assemblyTypes) Console.WriteLine(t.FullName);
Figure 2: Console screen
We can further extend this example to display the Methods and Public Properties contained under each type for this loaded Assembly.
The folliwng is the complete running code. I will walk you through the foreach loop section of the following code:
Figure 3: Complete running code
Inside the foreach loop, we define an array of MemberInfo[] and then, using the GetMembers() method of the Type class, we get all the member information.
-
- MemberInfo[] membersinfo = t.GetMembers(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance);
Note: Here I have specified the BindingsFlag, it's used for specifying the way in which reflection should do a search for the Member under each type. (In this case the search should be only one public member and second, the member declared in the Type and not inherited from the base type and third, a search for only instance members, in other words non-static members).
Not having
BindingsFlag will get all the information about the members for that specific type and in most cases, we would need only specify member info, so in such cases bindingFlags criteria would help.
- foreach (MemberInfo m in membersinfo) Console.WriteLine("Member type: {0}, member name: {1}.", m.MemberType, m.Name);
We then display the member type and the member name under each Type for the loaded Assembly.
Figure 4: Loaded Assembly
Learning Points:
- Learn what reflection is
- How to load a .NET Framework Assembly using Reflection
- Display the types from the loaded Assembly
- Display the members, Properties, Fields and Methods for each Type
- Use of BindingFlag
References
Note: This article had been earlier published on CodeProject. Other members suggested I upload it here for C# Corner members, this is my first ever article. If encouraged with suggestions and comments, I will continue to write more and publish.