C# 反射加载“系统”不带 FQN 的装配

发布于 2024-08-06 07:47:31 字数 381 浏览 2 评论 0原文

我想使用 Assembly.ReflectionOnlyLoad() 从某些 .NET 系统程序集(如 System、System.Windows.Forms 等)中提取 MemberInfos。现在,按照我的理解,我必须提供程序集的完全限定名称(包括版本信息等)或路径。但是,我希望我的代码不依赖于特定版本。相反,我只想提供部分名称(“System.Windows.Forms”),然后应加载该程序集的最新版本。另一种选择是 GAC 中的程序集路径(如果存在)。

我想一定有办法,因为 Visual Studio 似乎也这样做。当您在引用部分查看项目文件时,只能指定“System.Windows.Forms”而无法指定其他版本信息,但 VS 会在项目中引用正确的程序集版本。有谁知道我怎样才能做到这一点?

多谢!

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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

你好,陌生人 2024-08-13 07:47:31

ReflectionOnlyLoad() 最终调用私有 nLoad() 方法,并为 forIntrospection 参数设置 true。另一方面,具有您想要的程序集查找行为的 LoadWithPartialName() 也使用一组不同的参数(以及 false for 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);
}

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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文