Alex Mueller on Software and Technology 
Monday, July 18, 2005

I was looking for an example of reflection recently as I pondered where in some of my projects could I find sample code. Specifically, I was searching for something using Activator.CreateInstance(). While I did not have a sample using Activator.CreateInstance, I did have several examples of reflection using the provider pattern. I queried the internet looking for examples using Activator.CreateInstance, and found some results, but nothing I had in mind.

I have decided to share my example of reflection, and how it can be used in the provider pattern. Using simple examples of classes, I hope to get the point across with minimal complexity. I do not want to define reflection here, because there are limitless resources floating around the internet that will provide a much more thorough summary. I will, however, comment on reflection where necessary in my example. I do not want to define the provider pattern here as well for the same reasons. This journal entry is for the most part, an introduction, a quick reference, and a starting point for reflection, using one scenario where it can be applied.

The provider pattern uses reflection to dynamically load the class specified as the default provider in the application's web.config. In my web.config, I have a configuration section similar to what is seen below. My application is currently using a SQL data provider class, specified as my default provider. My other option is for an XmlFile provider. The point of the configuration is to allow the application to implement one of the provider options at runtime, giving the solution the flexibility to easily swap data providers when necessary. In order to do this, we need to access the web.config during application start and read in the necessary provider configuration. By doing this, we will be able to create a new class instance based upon its type.

<membership defaultProvider="SqlMembershipProvider">
    <providers>
        <add name = "SqlMembershipProvider"
                type = "MembershipProviders.SqlMembershipProvider, SqlMembershipProvider"
                connectionString = "^SqlConnectionString^"
        />
        <add name = "XmlFileMembershipProvider"
                type = "MembershipProviders.XmlFileMembershipProvider, XmlFileMembershipProvider"
        />
    </providers>
</membership>

The heart of the provider is the ability to create an instance of a class dynamically, and to determine how to instantiate the object. In order to begin this example, I need to create a Type object that will allow me to access metadata on a class, such as constructors, methods, properties, et cetera. The provider pattern should not hard-code the type name as I have done below, but use an alternative means, such as an accessible property on a provider object. Keep in mind the focus of this article is reflection and using the provider pattern as an example, not my implementation of the provider pattern itself.

// Get my class type at runtime
Type myType = Type.GetType( "MembershipProviders.SqlMembershipProvider, SqlMembershipProvider" );

The next step is to create our constructor object using our instance of the type object we just created. Before doing this, we need to create an array of types that describe our constructor. If we are going to get our constructor reference, we need to describe it, for example, MyProvider(), MyProvider(string connection), and MyProvider(string connection, int someInt), all have different signatures. By creating an array of Type objects, we will be able to call the appropriate constructor. In my example, the constructor I want to call requires three parameters of different types.

// We are anticipating a constructor that takes 3 parameters,
// the first is a string, the second is an int, the third is a boolean.
Type[] conTypes = new Type[3];
conTypes[0] = typeof( string );
conTypes[1] = typeof( int );
conTypes[2] = typeof( bool );

// Get the constructor that adheres to our parameters.
ConstructorInfo constructor = myType.GetConstructor( conTypes );

Next, we are going to invoke our constructor dynamically. Before doing this, we must define parameters to pass into our constructor when it is instantiated. In my example, I am going to pass in three objects to my constructor.

// Define the parameters to pass into our constructor when we call it.
object[] constructorParams = new object[3];
constructorParams[0] = "server=.;database=Pubs;uid=sa;pasword=pw";
constructorParams[1] = 52;
constructorParams[2] = false;

// Invoke the constructor dynamically, getting an instance of the class.
object myObject = constructor.Invoke( constructorParams );

At this point, we have created our class object at runtime using reflection. If we debug our application, we can see how the process occurs.

Wait a minute. What happened to Activator.CreateInstance()? It turns out we can use Activator.CreateInstance as well to create an instance of a specified type at runtime as well. Here is the same code example using Activator.CreateInstance().

// Get my class type at runtime
Type myType = Type.GetType( "MembershipProviders.SqlMembershipProvider, SqlMembershipProvider" );
object instance = Activator.CreateInstance( myType );

// We are anticipating a constructor that takes 3 parameters,
// the first is a string, the second is an int, the third is a boolean.
Type[] conTypes = new Type[3];
conTypes[0] = typeof( string );
conTypes[1] = typeof( int );
conTypes[2] = typeof( bool );

// Get the constructor that adheres to our parameters.
ConstructorInfo constructor = myType.GetConstructor( conTypes );

// Define the parameters to pass into our constructor when we call it.
object[] constructorParams = new object[3];
constructorParams[0] = "server=.;database=Pubs;uid=sa;pasword=pw";
constructorParams[1] = 52;
constructorParams[2] = false;

// Invoke the constructor dynamically, getting an instance of the class.
object myObject = constructor.Invoke( instance, constructorParams );

One final note. Using reflection is expensive and caching should be used wherever possible. In our example, it would be a good idea to have a condition where we check the cache to see if our constructor exists and is null. If it does exist, then we can proceed to defining the constructor parameters, then calling our invoke method on the cached reference.

// Test to see if our provide exists in cache
string providerCache = "Provider::" + OurWebConfig.DefaultProvider;
if( Cache[providerCache] == null )
{
    // our code example from above goes her
    
    Cache.Insert( providerCache, myType.GetConstructor(conTypes) );
}
// Call invoke
((ConstructorInfo)Cache[providerCache]).Invoke(constructorParams);

Further Reading:
Reflection Demystified
Reflection in .NET
Provider Model Design Pattern and Specification

Monday, July 18, 2005 3:39:16 PM (Mountain Standard Time, UTC-07:00) | Comments [0] | #
MuellerDesigns.net
Search
On This Page
The Split Personality of the Tester/Developer
Cross Site Scripting (XSS)
Creating files with FSUTIL
PowerShell Management Library for Hyper-V
Installing Windows 7
Installing Linux in Hyper-V
Internet Explorer 8 Release Candidate 1
PowerShell Documentation
Automate Daily Tasks with PowerShell
SketchPath XPath Editor
Software Testing - Revisited
Architecting Buildings and Software
NBCOlympics.com with Silverlight
Marker Interfaces and C# Attributes
Most Popular
JavaScript ReplaceAll Functionality
What is polymorphism?
What is composition?
Sorting with IComparable and IComparer
Applying the Observer Pattern in ASP.NET
MVP in ASP.NET
What is abstraction?
What is encapsulation?
What is a class?
What is inheritance?
Authentication in ASP.NET
Calendar Controls
XPathNavigator.CheckValidity new for 2.0
SQL Server 2005 Connection Issues
Auto-attach to process '[####] aspnet_wp.exe' on m...
What is an object?
FreeTextBox
VMWare and VPC
An Example of Reflection using C#
Changing File Ownership In Vista and Longhorn
Archive
Links
Categories
My Local Blog Map
Blogroll
About
Powered by:

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2010
MuellerDesigns.net

Sign In

Help Those In Need
The Hunger Site
Ronald McDonald House Charities (RMHC) of Western Washington & Alaska