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.

By Tim TrottIntroduction to Programming with C# • October 20, 2008
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. Guide to C# Data Types, Variables and Object Casting
  4. C# Operators: Arithmetic, Comparison, Logical and more
  5. Application Flow Control and Control Structures in C#
  6. Introduction to Object Oriented Programming for Beginners
  7. Introduction to C# Object-Oriented Programming Part 2
  8. C# Collection Types (Array,List,Dictionary,HashTable and More)
  9. Error and Exception Handling in C#
  10. Events, Delegates and Extension Methods
  11. Complete Guide to File Handling in C# - Reading and Writing Files
  12. Introduction to XML and XmlDocument with C#
  13. What is LINQ? The .NET Language Integrated Query
  14. Introduction to Asynchronous Programming in C#
  15. Working with Databases using Entity Framework
  16. All About Reflection in C# To Read Metadata and Find Assemblies
  17. Debugging and Testing in C#
  18. Introduction to ASP.Net MVC Web Applications and C#
  19. Windows Application Development Using .Net and Windows Forms
  20. Assemblies and the Global Assembly Cache in C#
  21. Working with Resources Files, Culture & Regions in .Net
  22. The Ultimate Guide to Regular Expressions: Everything You Need to Know
All About Reflection in C# To Read Metadata and Find Assemblies

Reflection does this by dynamically creating an instance of a type at runtime, depending on the data it finds. We can 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 used to get information about a non-instantiated type.

In this real-world example, we will see how we can use the name of a type (as a string) 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 will 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 handle it dynamically.

When the web service is invoked, it is passed an XML document containing 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 to 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 so the class name can be obtained from the source. In this example, the class is named cXML12021 to match the schema we will target.

You will need to code the implementation; the code below is only 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 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 inherited from the base class, so 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, implemented using the code in the specific class and instantiated through Reflection.

About the Author

Tim Trott is a senior software engineer with over 20 years of experience in designing, building, and maintaining software systems across a range of industries. Passionate about clean code, scalable architecture, and continuous learning, he specialises in creating robust solutions that solve real-world problems. He is currently based in Edinburgh, where he develops innovative software and collaborates with teams around the globe.

Related ArticlesThese articles may also be of interest to you

CommentsShare your thoughts in the comments below

My website and its content are free to use without the clutter of adverts, popups, marketing messages or anything else like that. 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?

New comments for this post are currently closed.