tags:

views:

407

answers:

1

I want to use Assembly.ReflectionOnlyLoad() to extract MemberInfos from some .NET system assemblies like System, System.Windows.Forms and so on. Now the way I undestand it, I must supply the fully qualified name of the assembly (inlcuding version info and all that) or the path. However, I want my code not to rely on a specific version. Instead, I only want to provide the partial name ("System.Windows.Forms") and then the newest version of this assembly should be loaded. An alternative would be a path of the assembly in the GAC if that exists.

I guess there has to be a way, as Visual Studio also seems to do this. When you look at a project file in the reference section, only "System.Windows.Forms" and no futher version info can be specified, yet VS takes the correct assembly version to be referenced in the project. Does anybody know how I can accomplish this?

Thanks a lot!

A: 

ReflectionOnlyLoad() eventually calls the private nLoad() method with true for the forIntrospection parameter. On the other hand, LoadWithPartialName(), which has the assembly lookup behavior you desire, also delegates to nLoad() with a different set of arguments (and false for forIntrospection). Replicating the partial call with introspection is a simple matter of reflection. :)

Update: It's actually not quite that simple. If nLoad() fails, we need to call the private EnumerateCache() and then a different InternalLoad(). The following works on my machine:

[Test]
public void TestReflectionOnlyLoadWithPartialName()
{
    var l = ReflectionOnlyLoadWithPartialName("System.Windows.Forms");

    Assert.IsTrue(l.ReflectionOnly);
}

public Assembly ReflectionOnlyLoadWithPartialName(string partialName)
{
    return ReflectionOnlyLoadWithPartialName(partialName, null);
}

public Assembly ReflectionOnlyLoadWithPartialName(string partialName, Evidence securityEvidence)
{
    if (securityEvidence != null)
        new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand();

    AssemblyName fileName = new AssemblyName(partialName);

    var assembly = nLoad(fileName, null, securityEvidence, null, null, false, true);

    if (assembly != null)
        return assembly;

    var assemblyRef = EnumerateCache(fileName);

    if (assemblyRef != null)
        return InternalLoad(assemblyRef, securityEvidence, null, true);

    return assembly;
}

private Assembly nLoad(params object[] args)
{
    return (Assembly)typeof(Assembly)
        .GetMethod("nLoad", BindingFlags.NonPublic | BindingFlags.Static)
        .Invoke(null, args);
}

private AssemblyName EnumerateCache(params object[] args)
{
    return (AssemblyName)typeof(Assembly)
        .GetMethod("EnumerateCache", BindingFlags.NonPublic | BindingFlags.Static)
        .Invoke(null, args);
}

private Assembly InternalLoad(params object[] args)
{
    // Easiest to query because the StackCrawlMark type is internal
    return (Assembly)
        typeof(Assembly).GetMethods(BindingFlags.NonPublic | BindingFlags.Static)
        .First(m => m.Name == "InternalLoad" && m.GetParameters()[0].ParameterType == typeof(AssemblyName))
        .Invoke(null, args);
}
dahlbyk