Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • JavaScript • Angular
Contact   •   Articles   •   Products   •   Support   •   Search
Ad-free experience sponsored by:
ASPOSE - the market leader of .NET and Java APIs for file formats – natively work with DOCX, XLSX, PPT, PDF, images and more

Dynamic Type Invokation in .NET


:P
On this page:

I'm working on an application that's dynamically mapping requests to a variety of classes. Based on the inbound request a lookup into various meta data tables occurs and based on this string based look up data we decide which types to invoke. .NET makes it pretty easy to dynamically invoke types (and execute code) using Reflection, but finding the right methods for each of these approaches is not always so easy - there are a lot of different ways to arrive at the same operation.

So here's a quick summary of how to invoke types dynamically and a few type instantiation routines I have in my library.

The simplest way to invoke a type of course is to just instantiate it. You can simply use new() on any type and invoke it constructor. Behind the scenes .NET actually wires up instantiation code by finding the type and calling the appropriate constructor for the parameters you've passed and returns a type instance.

So a direct instantiation looks like this:

BaseSummaLpReport report = new SummaLpManager.Daily_Jrn_SampRpt();

Invoke through Constructor

So let's assume that you only have type information available, and you need to dynamically invoke the type. This may look a little silly without context because it's not all that often that you end up with a type and need to instantiate a class - a couple of common scenarios are add-ins and documentation generation. In the sample below I just provide the type for demonstration purposes.You know the assembly where the types live because the user registered an assembly or stored in a special location, and you use a marker interface or attributes to pick out the types that can work for an add-in for example. To invoke the add-in you have to dynamically load it because you don't know the concrete type name.

Constructor loading is fairly low level and somewhat verbose and it looks something like this:

BaseSummaLpReport report = typeof(SummaLpManager.Daily_Jrn_SumRpt).GetConstructor(Type.EmptyTypes).Invoke(null) 
                                              as BaseSummaLpReport;

This is something akin to what .NET actually turns a new() instruction into - it's basically invoking the constructor. Using GetConstructor() can be pretty useful because you can cache constructors. If you end up repeatedly calling a dynamically invoked constructor caching the constructor instance can drastically improve invokation performance compared to dynamically looking up the constructor each time.

Constructor instantiation is pretty efficient but it can also get a little cumbersome because you have to find the exact parameter signature to call. Notice the call to GetConstructor with Type.EmptyTypes which basically is the no parameter version. If you have parameters, an array of types for each of the parameters must be passed.

Typed Instantiation with Activate.CreateInstance()

To make instantion a bit easier, there's the the static Activator class which provides a handy CreateInstance() method that can be invoked with a type. There's a plain parameter version and a generic version.

BaseSummaLpReport report = Activator.CreateInstance(typeof(SummaLpManager.Daily_Jrn_SumRpt)) 
as BaseSummaLpReport;

This version supports a number of overloads (13 of them) and one of them allows for a list of parameters for activating specific constructors.

The generic version works similarly but it doesn't support any parameters.

BaseSummaLpReport report = Activator.CreateInstance<SummaLpManager.Daily_Jrn_SumRpt>();

One advantage of the generic version is that you don't need to explicitly do type conversion - the compiler automatically fixes up the type properly.

I would have thought the generic version would be faster and allow caching of the constructor potentially. However, running some quick perf tests, it looks like the non-generic version is actually significantly faster (not that it matters much - 10000 iterations registered around 8 milliseconds and 14 respectively).

Invoking by String

Finally you might also want to invoke an object just by its type name, which really comes back to the problem I mentioned above. In our app we have lookup tables in a database that match requests with specific class names. These tables are loaded on startup and classes are then invoked on the fly. There are two different sets: request handlers and report handlers. Both are based on the request's scriptname and translated.

There's no direct support for creating an instance of a type, but you can sort of get a type from a string by using Type.GetType(). It takes string parameter and returns a type from a fully qualified type name (namespace + type name). The following works:

Response.Write(Type.GetType("System.Version"));

If you look at the documentation for GetType() you'll find there's quite a bit of ambiguity and it really only works if you specify a fully qualified AssemblyQualifiedName which is useless in most dynamic scenarios. GetType() works with simple namespacae + typename only if the type exists in the current assembly or in mscorlib. Strike that as a generic routine.

So to get a type more reliably, albeit a lot more slowly is to write a small routine that walks the types of all loaded assemblies:

/// <summary>
/// Helper routine that looks up a type name and tries to retrieve the
/// full type reference in the actively executing assemblies.
/// </summary>
/// <param name="TypeName"></param>
/// <returns></returns>
public static Type GetTypeFromName(string TypeName)
{
 
    Type type = Type.GetType(TypeName);
    if (type != null)
        return type;
 
    // *** try to find manually
    foreach (Assembly ass in AppDomain.CurrentDomain.GetAssemblies())
    {
        type = ass.GetType(TypeName, false);
 
        if (type != null)
            break;
 
    }
    return type;
}

Once you have a type instance you can then use Activator.CreateInstance to instantiate it. To wrap this up as well you'd get a CreateInstance from string:

/// <summary>
/// Creates an instance of a type based on a string. Assumes that the type's
/// </summary>
/// <param name="typeName"></param>
/// <param name="args"></param>
/// <returns></returns>
public static object CreateInstanceFromString(string typeName, params object[] args)
{
    object instance = null;
    Type type = null;
 
    try
    {
        type = GetTypeFromName(typeName);
        if (type == null)
            return null;
 
        instance = Activator.CreateInstance(type, args);
    }
    catch (Exception ex)
    {
        return null;
    }
 
    return instance;
}

COM Object Invokation

COM objects can also be invoked by first retrieving a .NET COM wrapper type from a ProgId with Type.CreateTypeFromProgId:

/// <summary>
/// Creates a COM instance from a ProgID. Loads either
/// Exe or DLL servers.
/// </summary>
/// <param name="progId"></param>
/// <returns></returns>
public static object CreateComInstance(string progId)
{
    Type type = Type.GetTypeFromProgID(progId);
    if (type == null)
        return null;
 
    return Activator.CreateInstance(type);
}

Performance

It's interesting to compare the various different mechanisms. Obviously pure type instantiation is by far the fastest mechanism. In fact, I was running some very basic performance tests over the different mechanisms and as i did so with the direct instance results I got 0 milliseconds on the first few runs. I had to add some code to make sure the compiler wasn't just optimizing out dead code <s>, but sure enough, even with some dynamic assigment code times of objects without much state is extremely fast.

Creating instances using the CreateInstanceFromString method above on the other hand is a LOT slower. In fact for a custom type of mine in a Web app it took over 1000 times longer to run the same 10000 iterations. But keep in mind we're talking about 10000 iterations in about 1 second, so it's not like this will stop your app dead unless you run the string instantiation in a loop.

Instantiating an existing type is much faster by comparison - running only 30-40 times slower than raw instantiation. Relatively speaking that's a heck of a lot better.

If you do resort to string based instantiation frequently by creating lots of objects or creating them in a loop, consider caching either the type or even better the constructor. Storing reusable types in a Hashtable for reuse is an easy way to improve performance on repetive tasks as all the slow lookup code falls away. Most of the slowness in Reflection comes from doing type and member lookups and once you have the target member to invoke it's comparatively fast.

Dynamic invokation is not something you do every day - it's a specialty scenario but these days with so much meta programming and layers and layers of pluggable and adapter based code  there's more and more of it around. Knowing how to get an instance is always nice.

For instance did I tell you the one about... nah, maybe another time...

Posted in .NET  CSharp  

The Voices of Reason


 

Bertrand Le Roy
August 30, 2007

# re: Dynamic Type Invokation in .NET

Funny you would be mentioning that, I've been doing something along those lines in a prototype recently, but I took yet another approach: build providers. If the types you need to instantiate are configurable but known at compile-time, you can leverage the compilation engine to generate the fastest factory code possible: at runtime, it's just regular static instantiation. Making sense?

Rick Strahl
August 30, 2007

# re: Dynamic Type Invokation in .NET

Yeah Build Providers are great that way, they let you inject just about anything during compilation. Hmmm... actually now that you mention it that might actually work for us too. We know what the types are at site compilation time - we could look it up in the meta data. Not sure how to get it assigned and passed back dynamically at runtime though? It would have to be a static factory method or something like that that looks up a string value and generates the appropirate static invoke code. Interesting idea.

OTOH, I don't think performance is much of an issue for this particular scenario I mentinoed. There will be exactly two objects created on the fly - one of the script handler and one for the report handler. I don't think it's worth optimizing in this particular situation <s>.

Bertrand Le Roy
August 30, 2007

# re: Dynamic Type Invokation in .NET

Drop me a line if you need more details, but in my implementation, I have strongly-typed factories (for Visual Studio IntelliSense where applicable, which is quite awesome) that you can also get to through string-parametered methods which just return some interface type. There could also be generic factories if that applies to what you're doing.

SimoneB
August 31, 2007

# re: Dynamic Type Invokation in .NET

Why not IoC?

cmills2000
November 02, 2007

# re: Dynamic Type Invokation in .NET

Great article... gave me some good ideas on making a dynamically configurable site in ASP.NET with control names read-in from a db.

Aaron
April 22, 2008

# re: Dynamic Type Invokation in .NET

You always seem to have the answer when I cannot find it elsewhere.

Richard
October 04, 2008

# re: Dynamic Type Invokation in .NET

Nice one. Great article. I was doing a quick Google for an article like this, to decide if i should take the time to decouple the writers for a replication subsystem Im building from the application specific types.

Basically i have my code sufficiently factored out to the point where i figure i can just put the table writer ids in the config file and have them dynamically read and constructed at run time.
That way I'll have a reuseable replication system whereby only the table writers need to be rewritten on each reuse - the subsystem itself doesn't care about the type nor shape of your backing store.

Your straightforward way of explaining things means this will get done today, as opposed to it being put on the back burner, for a time when i have more time to "investigate".

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2021