Click here to Skip to main content
Click here to Skip to main content

Loading .NET types while ignoring version numbers

, 16 Oct 2009 MIT
Rate this:
Please Sign up or sign in to vote.
This article shows how to use AssemblyResolve to customize Type loading.

Introduction

Type.GetType("typeName, assemblyName, version, culture") is a common way to load a type object. Unfortunately, the version of the assembly is frequently newer than the one given by the string. Your code might have saved the type name using the Type.AssemblyQualifiedName property, which includes all assembly information, and later tried to load that type, even though the version might have changed. This article will demonstrate an easy way to load a type while ignoring the specific assembly version.

Code

During the normal Type.GetType() call, the AppDomain object will raise an AssemblyResolve event for any assembly it cannot find. (The type string may contain more than one subtype -- Generics.) An optional event handler may load and return an alternative assembly, or null if no assembly is available.

The OnAssemblyResolve handler receives the unresolved assembly name, uses the AssemblyName object to parse it, and attempts to load an assembly with just the name, without any other information.

AssemblyResolve is global for the domain, so we must make sure that other threads, that might potentially try to resolve a type at the same time, do not unintentionally use the same functionality. A boolean field _isGetTypeRunningOnThisThread marked with the [ThreadStatic] attribute cleanly solves this problem.

/// <summary>
/// Load type using <see cref="Type.GetType(string)"/>, and if fails, 
/// attempt to load same type from an assembly by assembly name, 
/// without specifying assembly version or any other part of the signature
/// </summary>
/// <param name="typeName">
/// The assembly-qualified name of the type to get.
/// See System.Type.AssemblyQualifiedName.
/// If the type is in the currently executing assembly or in Mscorlib.dll, it 
/// is sufficient to supply the type name qualified by its namespace.
/// </param>
public static Type GetTypeFromAnyAssemblyVersion(string typeName)
{
    // If we were unable to resolve type object
    //    - possibly because of the version change
    // Try to load using just the assembly name,
    // without any version/culture/public key info
    ResolveEventHandler assemblyResolve = OnAssemblyResolve;

    try
    {
        // Attach our custom assembly name resolver,
        // attempt to resolve again, and detach it
        AppDomain.CurrentDomain.AssemblyResolve += assemblyResolve;
        _isGetTypeRunningOnThisThread = true;
        return Type.GetType(typeName);
    }
    finally
    {
        _isGetTypeRunningOnThisThread = false;
        AppDomain.CurrentDomain.AssemblyResolve -= assemblyResolve;
    }
}

[ThreadStatic] private static bool _isGetTypeRunningOnThisThread;

private static Assembly OnAssemblyResolve(object sender, ResolveEventArgs args)
{
    Assembly assembly = null;

    // Only process events from the thread that started it, not any other thread
    if (_isGetTypeRunningOnThisThread)
    {
        // Extract assembly name, and checking it's the same as args.Name
        // to prevent an infinite loop
        var an = new AssemblyName(args.Name);
        if (an.Name != args.Name)
            assembly = ((AppDomain) sender).Load(an.Name);
    }

    return assembly;
}

License

This article, along with any associated source code and files, is licensed under The MIT License

Share

About the Author

Yuri Astrakhan
Architect
United States United States
Yuri works in a small hedge fund in New York, designing various aspects of the trading platform. In the spare time, Yuri participates in various open source initiatives, such as Wikipedia, where he designed and implemented MediaWiki API - http://www.mediawiki.org/wiki/API
 
Yuri writes from New York

Comments and Discussions

 
GeneralEvent subscribtion and multithreading PinmemberAndrew Bibitchev12-Jan-10 2:50 
QuestionWhat's the point? Pinmemberdojohansen17-Oct-09 23:07 
I have one major and a few very minor gripes with this.
 
The major one is that the code is, as far as I can see, pointless. If you really don't care what version of an assembly you have, why use Type.GetType(string) with a fully qualified string in the first place? In other words, why ask for a specific version and then make Type.GetType() not do what it's supposed to, instead of just asking for any version in the first place?
 
The minor gripes:
 
Naming convention: "OnAssemblyResolve" should, by .net library developer guidelines, be a protected method responsible for *raising* an event named AssemblyResolve. Event handlers are named after the type raising the event and the event name, and the conventional name here would be AppDomain_AssemblyResolve. (Then again Microsoft themselves haven't followed their own guidelines with this event, since conventionally event handlers return void and communicate with their caller only via the event data object.)
 
Pointless line: ResolveEventHandler assemblyResolve = OnAssemblyResolve;
 
Error: If the type is in the currently executing assembly or in Mscorlib.dll ...
 
I believe this should be "If the type is in the current AppDomain or in the GAC".
GeneralMy vote of 3 [modified] Pinmemberdojohansen17-Oct-09 22:39 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.141223.1 | Last Updated 16 Oct 2009
Article Copyright 2009 by Yuri Astrakhan
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid