Click here to Skip to main content
15,880,608 members
Articles / Programming Languages / C#

Loading .NET types while ignoring version numbers

Rate me:
Please Sign up or sign in to vote.
4.56/5 (5 votes)
16 Oct 2009MIT1 min read 28.6K   13   4
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.

C#
/// <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


Written By
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 Pin
Andrew Bibitchev12-Jan-10 1:50
Andrew Bibitchev12-Jan-10 1:50 
Yuri, how do you think: is there any problem with lines
AppDomain.CurrentDomain.AssemblyResolve += assemblyResolve;
and
AppDomain.CurrentDomain.AssemblyResolve -= assemblyResolve;
when method called from different threads?

MSDN says that neither AppDomain’s instance members nor MulticastDelegate’s instance member are thread-safe.

May be we should subscribe on AppDomain.CurrentDomain.AssemblyResolve only once and forever in thread-safe manner (e.g. from static constructor of our class)?
QuestionWhat's the point? Pin
dojohansen17-Oct-09 22:07
dojohansen17-Oct-09 22:07 
GeneralMy vote of 3 [modified] Pin
dojohansen17-Oct-09 21:39
dojohansen17-Oct-09 21:39 
GeneralRe: My vote of 3 [modified] Pin
Bunny99s14-May-16 15:05
Bunny99s14-May-16 15:05 

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

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