- Introduction to Programming with C# 7
- C# Programming Fundamentals
- Introduction to Object-Oriented Programming
- C# Object-Oriented Programming Part 2
- Flow Control and Control Structures in C#
- C# Data Types, Variables and Casting
- C# Collection Types (Array, List, Dictionary, Hash Table)
- C# Operators: Arithmetic, Comparison, Logical and more
- Using Data in C# 7 with ADO.Net & Entity Framework
- LINQ: .NET Language Integrated Query
- Error and Exception Handling in C#
- Advanced C# Programming Topics
- Reflection in C#
- What Are ASP.Net Webforms
- Introduction to ASP.Net MVC
- Windows Application Development
- Assemblies and the Global Assembly Cache in C#
- Working with Resources Files, Culture & Regions
- Regular Expressions in C#
- Introduction to XML with C#
- Complete Guide to File Handling in C#
We can have a look at a few simple objects and get their type.
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 object
typeof 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 a number of sources, including from an XML document, database, file, 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 a number of 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.
<!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.
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.
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 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.
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.
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 actually create an instance of the base class which takes the form of the cXML12021 class.
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.
This post is part of the series Introduction to Programming with C#. Use the links below to advance to the next tutorial in the couse, or go back and see the previous in the tutorial series.