Reflection Basics in .NET

Arguably one of the most advanced features of the .NET Framework is the ability to write dynamic code and discover type information at runtime. As it’s such an advanced feature, and one that few people use to its full extent, looking at and understanding code that uses reflection can take a bit of time to get your head around. This article demonstrates some of the basics of reflection by showing both non-reflection and reflection code written to send an e-mail. This article has been written to give people a feel for reflection, and doesn’t really demonstrate a particular usefulness.

Firstly, I’ll show a simple snippet of code that can be used to send an e-mail. The code works by creating a mail client (SmtpClient) for a specified mail server. We then set the client’s credentials using the NetworkCredentials class. We then create a MailMessage object with a from and a to address, and finally send the message.

  1. SmtpClient client = new SmtpClient(
  2.     "mail.yoursite.com");
  3. client.Credentials = new NetworkCredential(
  4.     "you@yoursite.com", "yrpa55wrd");
  5. MailMessage message = new MailMessage(
  6.     "you@yoursite.com", "someone@gmail.com");
  7. message.Subject = "Automated Message";
  8. message.Body = "Message sent using Mail classes.";
  9. client.Send(message);

Hopefully that should be fairly easy to follow. Before we go on to the version written using reflection, I’ll just give abrief overview of some of the classes used in reflection. Most work here is done using MemberInfo classes – classes that inherit from the MemberInfo class. These include ConstructorInfo, MethodInfo, PropertyInfo, EventInfo, FieldInfo, LocalVariableInfo, and less obviously, MethodBase and Type. ConstructorInfo and MethodInfo actually inherit from MethodBase, and therefore from MemberInfo indirectly. MathodBase describes a member of a type that contains executable code. Apart from these classes, we will use the Assembly class to load assemblies and access types. You can also access types using typeof() and GetType(), but you’d have to have access to the approprate dlls at compile time for that.

Now we’re going to change the above snippet to do everything using reflection. First of all, we need to load the assemblies containing the types we need to use. These types are SmtpClient, MailMessage, NetworkCredentials and String (although we will use instances of strings in a non-reflective way to save time). The first three reside in System.dll, and String resides in mscorlib.dll. In the snippet below, we load these assemblies using the static LoadFrom method of the Assembly class, and get the types we need using the instance method GetType of Assembly. The variable ‘path’ is the location of the .NET 2.0 class libraries which is usually %windir%/Microsoft.NET/Framework/v2.0.50727/.

  1. // Load System.dll and get the Types we need from it.
  2. Assembly system = Assembly.LoadFrom(
  3.     Path.Combine(path, "System.dll"));
  4. Assembly mscorlib = Assembly.LoadFrom(
  5.     Path.Combine(path, "mscorlib.dll"));
  6. Type tSmtpClient = system.GetType(
  7.     "System.Net.Mail.SmtpClient", true);
  8. Type tMailMessage = system.GetType(
  9.     "System.Net.Mail.MailMessage", true);
  10. Type tNetworkCredential = system.GetType(
  11.     "System.Net.NetworkCredential", true);
  12. Type tString = mscorlib.GetType("System.String", true);

We provide the parameter true after our type name because if the type doesn’t exist in that assembly, we want an exception to be thrown – all the types declared are needed for proper execution, if one fails to load, we want to fail at exactly that point.

Next we need to create the client. This is done in two steps – we get an instance of ConstructorInfo by calling the instance method Type.GetConstructor and specifying the method signature in a Type array. Then we call the method, specifying the actual parameters in an object array and get our SmtpClient instance back as an object.

  1. // Get the SmtpClient constructor that takes a host name
  2. // as a parameter, and invoke it to get our SmtpClientObject.
  3. ConstructorInfo ctor = tSmtpClient.GetConstructor(
  4.     new Type[] { tString });
  5. object client = ctor.Invoke(
  6.     new object[] { "mail.yoursite.com" });

Similarly, we’ll create a NetworkCredentials instance for the user name and password for the mail server.

  1. // Create our NetworkCredentials object for authentication
  2. // on the mail server.
  3. ctor = tNetworkCredential.GetConstructor(
  4.     new Type[] { tString, tString });
  5. object credentials = ctor.Invoke(
  6.     new object[] { "you@yoursite.com", "yrpa55wrd" });

Next we need to set the Credentials property of our SmtpClient object. We use Type.GetProperty(), then PropertyInfo.GetSetMethod() to get the MethodInfo object for the method to call. We can then invoke the MethodInfo object using our client object and our credentials.

  1. // Get the Credentials property from the SmtpClient type,
  2. // and invoke the set method.
  3. PropertyInfo creds = tSmtpClient.GetProperty("Credentials");
  4. MethodInfo setCreds = creds.GetSetMethod();
  5. setCreds.Invoke(client, new object[] { credentials });

We’ll bring those two concepts together to create our MailMessage – first creating it using ConstructorInfo, and then setting a couple of properties:

  1. // Create the MailMessage instance, using the constructor that
  2. // takes two strings – a from and a to address.
  3. ctor = tMailMessage.GetConstructor(
  4.     new Type[] { tString, tString });
  5. object message = ctor.Invoke(
  6.     new object[] { "you@yoursite.com", "somone@gmail.com" });
  7.  
  8. // Set the subject and body properties.
  9. PropertyInfo subject = tMailMessage.GetProperty("Subject");
  10. MethodInfo setSubject = subject.GetSetMethod();
  11. setSubject.Invoke(
  12.     message, new object[] { "Automated Message" });
  13.  
  14. PropertyInfo body = tMailMessage.GetProperty("Body");
  15. MethodInfo setBody = body.GetSetMethod();
  16. setBody.Invoke(message, new object[] {
  17.     "Message sent using reflection." });

Finally, we’ll send the message using SmtpClient’s Send method:

  1. // Get the Send method and invoke it using our SmtpClient
  2. // and MailMessage objects.
  3. MethodInfo send = tSmtpClient.GetMethod(
  4.     "Send", new Type[] { typeof(System.Net.Mail.MailMessage) });
  5. send.Invoke(client, new object[] { message });

So there we have it. I hope this has given you a basic understanding of how reflection works, but the only way you can really learn is to try it for yourself. Happy reflectioning!

Share and Enjoy:
  • Print
  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Yahoo! Buzz
  • Twitter
  • Google Bookmarks
  • email
  • LinkedIn
  • Technorati

Leave a Reply

Your email address will not be published. Required fields are marked *