All About Reflection in C# To Read Metadata and Find Assemblies

Reflection is when managed code can read its own metadata to find assemblies and modify its behaviour according to input.

Introduction to Programming with C#

This article is part of a series of articles. Please use the links below to navigate between the articles.

  1. Learn to Program in C# - Full Introduction to Programming Course
  2. Introdution to Programming - C# Programming Fundamentals
  3. Introduction to Object Oriented Programming for Beginners
  4. Introduction to C# Object-Oriented Programming Part 2
  5. Application Flow Control and Control Structures in C#
  6. Guide to C# Data Types, Variables and Object Casting
  7. C# Collection Types (Array,List,Dictionary,HashTable and More)
  8. C# Operators: Arithmetic, Comparison, Logical and more
  9. Using Entity Framework & ADO.Net Data in C# 7
  10. What is LINQ? The .NET Language Integrated Query
  11. Error and Exception Handling in C#
  12. Advanced C# Programming Topics
  13. All About Reflection in C# To Read Metadata and Find Assemblies
  14. What Are ASP.Net WebForms
  15. Introduction to ASP.Net MVC Web Applications and C#
  16. Windows Application Development Using .Net and Windows Forms
  17. Assemblies and the Global Assembly Cache in C#
  18. Working with Resources Files, Culture & Regions in .Net
  19. The Ultimate Guide to Regular Expressions: Everything You Need to Know
  20. Introduction to XML and XmlDocument with C#
  21. Complete Guide to File Handling in C# - Reading and Writing Files

Reflection does this by dynamically creating an instance of a type at runtime depending on the data it finds. We can have a look at a few simple objects and get their type.

C#
string test = "test";
Console.WriteLine(test.GetType().FullName);
Console.WriteLine(typeof(Int32).FullName);
Console.ReadKey();

The Type class is the foundation of Reflection. Type is a type of type Type. It serves as runtime information about an assembly, a module or a type. Every class has the function GetType which is inherited from the objecttypeof is a universal method which is used to get information about a non-instantiated type.

In this real-world example, we are going to see how we can use the name of a type (as a string) and use that to create an instance of a specific object.

There are many occasions when you need to convert a string into an instance of a class. For example when you need to create an instance of a class, but the exact type is unknown. This example will show you how to get a type from a string and use reflection to create an instance of it.

The string can come from several sources, including an XML document, database, file, or configuration object.

This example is going to be loosely based on a Punchout system, where a customer will send an XML document to the web service.

The XML document can be of any number of types (the most common being cXML) and the application needs to know how to dynamically handle it.

When the web service is invoked, it is passed an XML document which contains several elements to identify the sender and authenticate. Since the XML document can be of any number of standards (or even a custom schema), the application needs to know what data is in what field.

In this example for a cXML document, the header contains the schema information which we will use to identify the message format.

C#
<!DOCTYPE cXML SYSTEM "http://xml.cXML.org/schemas/cXML/1.2.021/cXML.dtd">

I have a function that will convert this schema into a string "cXML12021".

We then define a base class which contains all the common properties we need to know about for the order. In this example, I'm only including a few for the sake of simplicity.

C#
public class PunchoutBaseClass
{
  public abstract string CustomerName;
  public abstract string DeploymentMode;
  public abstract string SelectedService;
}

After this, you will need some classes that will implement this class. They should be named in such a way that the class name can be obtained from the source. In this example, the class is named cXML12021 to match the schema we are going to target.

You will need to code the actual implementation; the code below is only given as an example.

C#
public class cXML12021 : PunchoutBaseClass
{
  public override string CustomerName
  {
    get { return XmlDocument.SelectSingleNode("/cXML/Sender/Credential/Identity").InnerText; }
  }
  public override string DeploymentMode
  {
    get { return XmlDocument.SelectSingleNode("/cXML/Request/@deploymentMode").InnerText; }
  }
  public override string SelectedService
  {
    get { return XmlDocument.SelectSingleNode("/cXML/Request/ProviderSetupRequest/SelectedService").InnerText; }
  }
}

public class uniqCustFormat : PunchoutBaseClass
{
  public override string CustomerName
  {
    get { return XmlDocument.SelectSingleNode("/Setup/UserID").InnerText; }
  }
  public override string DeploymentMode
  {
    get { return XmlDocument.SelectSingleNode("/Setup/Mode").InnerText; }
  }
  public override string SelectedService
  {
    get { return XmlDocument.SelectSingleNode("/Setup/RequestType").InnerText; }
  }
}

You should be able to see that although the two classes expose the same properties to the developer, the actual implementation is different.

Now we know what class to instantiate, and we have two classes that inherit from the base class we can use a short snippet to get the .Net assembly type.

This is the part where we use reflection. It essentially iterates through all the types in all the loaded assemblies until it finds one that matches the schema name. When found it returns the type.

C#
public static Type StringToType(string typeName)
{
    foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
    {
        Type foundType = assembly.GetType(typeName);

        if (foundType != null)
            return foundType;
    }
    return null;
}

Usage is simply a case of passing in a string containing cXML12021.

C#
string XmlType = "cXML12021"; / This can be generated dynamically
Type t = StringToType(XmlType);

Now, all we need to do is use the powerful reflection classes to create an instance of the cXML12021 class. This can only be done because we are using a base class. We create an instance of the base class which takes the form of the cXML12021 class.

C#
if (t != null)
{
  PunchoutBaseClass cXml = (PunchoutBaseClass)Activator.CreateInstance(t);
  Response.Write(cXml.CustomerName);
}
else
{
  Response.Write("Class name not found!");
}

Now we can use the methods defined in the base class which are implemented using the code in the specific class in instantiated through reflection.

Was this article helpful to you?
 

Related ArticlesThese articles may also be of interest to you

CommentsShare your thoughts in the comments below

If you enjoyed reading this article, or it helped you in some way, all I ask in return is you leave a comment below or share this page with your friends. Thank you.

There are no comments yet. Why not get the discussion started?

We respect your privacy, and will not make your email public. Learn how your comment data is processed.