C # Отражающая нагрузка «Система» в сборе без FQN - PullRequest
2 голосов
/ 02 октября 2009

Я хочу использовать Assembly.ReflectionOnlyLoad () для извлечения MemberInfos из некоторых системных сборок .NET, таких как System, System.Windows.Forms и так далее. Теперь, как я понимаю, я должен предоставить полное имя сборки (включая информацию о версии и все такое) или путь. Однако я хочу, чтобы мой код не зависел от конкретной версии. Вместо этого я хочу предоставить только частичное имя («System.Windows.Forms»), и тогда должна быть загружена самая новая версия этой сборки. Альтернативой может быть путь сборки в GAC, если таковой существует.

Я думаю, что должен быть способ, так как Visual Studio, похоже, тоже делает это. Когда вы смотрите на файл проекта в справочном разделе, только «System.Windows.Forms» и никакая дополнительная информация о версии не могут быть указаны, но VS принимает правильную версию сборки, на которую ссылается проект. Кто-нибудь знает, как я могу это сделать?

Большое спасибо!

1 Ответ

0 голосов
/ 02 октября 2009

ReflectionOnlyLoad() в конечном итоге вызывает приватный метод nLoad() с true для параметра forIntrospection. С другой стороны, LoadWithPartialName() с желаемым поведением поиска сборки также делегирует nLoad() с другим набором аргументов (и false для forIntrospection). Воспроизведение частичного вызова с помощью самоанализа является простым вопросом для размышления. :)

Обновление: На самом деле все не так просто. Если nLoad() терпит неудачу, нам нужно вызвать приватный EnumerateCache(), а затем другой InternalLoad(). На моей машине работает:

[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);
}
...