【问题标题】:Good way to preload .NET assembly预加载 .NET 程序集的好方法
【发布时间】:2011-06-21 05:02:55
【问题描述】:

在我的应用程序中,我需要在鼠标点击时显示一个表单。问题是该表单位于另一个程序集中,并且由于程序集加载的惰性性质,当按下鼠标按钮时,该程序集可能尚未加载。因此,在表格最终出现之前,我所拥有的是非常明显的停顿。

通过在我的初始化方法中调用new FormFromAnotherAssembly(),我能够想出一个愚蠢的修复方法。当然,这已经解决了问题,停顿不再存在,但它非常难看。我喜欢这个解决方案的唯一一点是,如果我想使用 Assembly.Load 之类的东西,我不必弄乱路径和程序集名称。

那么,如果我想确保在我真正需要之前加载程序集,有什么好的、健壮的解决方案?

提前致谢。

【问题讨论】:

  • 您忽略了一个好的解决方案。唯一的另一个是获得更快的硬盘驱动器。如果您在过去 6 个月内没有对磁盘进行碎片整理,那么现在是个好时机。

标签: c# reflection assemblies


【解决方案1】:

在您的 init 中显式预加载可能仍然是您的最佳选择。

typeof(SomeTypeFromAnotherAssembly) 应该足够了 - 以及一些无法优化的不透明方法;也许:

GC.KeepAlive(typeof(SomeTypeFromAnotherAssembly));

这避免了new。请注意,这将被加载,而不是 JITted 等。

如果你愿意,你可以在 BG 线程上做:

private static void LoadSomeStuff(object state) {
    GC.KeepAlive(typeof(SomeTypeFromAnotherAssembly));
}
...
ThreadPool.QueueUserWorkItem(LoadSomeStuff);

【讨论】:

  • 谢谢你,Marc,但如果我想加载和 JITted 等怎么办?因为看起来加载程序集只是问题的一部分,而且暂停仍然存在。
  • @Dyppl - JIT 相对较快 - 我建议问题是加载 other (下游)程序集并加载其他资源。如果你调试你应该能够看到还有什么加载...
  • 嗯,是的,不幸的是,该表单是 WPF 表单,并且拖了很多废话。
  • @Dyppl 那么您可能别无选择,只能创建一个表格来准备一切;你应该只在 UI 线程中这样做。
  • 谢谢,我不知道我最终会做什么,但你的解决方案非常适合我所描述的任务,所以我正在标记它
【解决方案2】:

我相信 Assembly.Load 是一种方式。

在应用程序启动期间,您应该找到模块、插件或任何其他运行时可插入的并将它们的程序集加载到应用程序的域 (AppDomain) 中。

或者另一个更好的选择:你为什么不为此使用控制反转?

您可以为此使用温莎城堡。假设您有 4 个表单要在运行时加载,因此,您可以创建 Form 类的 4 个组件,它们的实现是程序生命周期中要加载的 4 个表单。

如何使用这种方法进行预加载?您只需解决所有 Form 类型的依赖项/组件即可:

container.ResolveAll<Form>();

稍后你会得到一个特定的表格:

container.Resolve<Form>("CustomersForm"); // Just an example

如果您不知道控制反转,请注释掉,我会帮助您,没问题! :)

【讨论】:

  • 好吧,想想你是否会有很多运行时加载的表单。如果不是这种情况,是的,这对你来说太过分了。
  • 嗯,目前不太可能,不过还是谢谢你,有需要我会试试你的解决方案。
  • 顺便说一句,你为什么不做一个手工制作的控制反转,就像在你的应用程序设置中输入表单的完整程序集限定名称一样简单,然后做类似 YourForm.Preload 之类的事情() - 返回表单 - 这将执行 Type.GetType(Properties.Settings.Default.FormAssemblyName); ? (这意味着其他表单的程序集位于 bin 目录中,但如果不是您的情况,只需在设置中提供完整的物理路径,然后在 SomeForm.Preload() 中执行 Assembly.Load)
  • 我希望有一个更优雅的解决方案。如果框架知道在哪里可以找到表单以及如何加载它,我为什么要经历这一切?它只是在他真正需要之前不会这样做,所以我想让他早一点需要它。当然,我可以做到这一切,但问题或多或少是“有没有更好的方法来做到这一点”。
  • 哦,那么,也许您还有另一个简单的选择:Asssembly.GetReferencedAssemblies。此方法按一个返回所有引用的程序集。也就是说,您可以在应用程序开始调用 Assembly.Load(AssemblyName) 时自动预加载所有引用的程序集。这几乎是一样的,但你避免使用文字,因为应用程序集将通过 Assembly.GetExecutingAssembly 检索。
【解决方案3】:

我认为最简单的方法是在 Assembly.Load() 中使用程序集名称:

System.Reflection.Assembly.Load("ICSharpCode.AvalonEdit");

您可以在 Visual Studio 中的引用属性下找到程序集名称:

这样你可以避免输入 dll 文件路径等。我用它来加速使用这个 DLL 的对话框的加载。一旦程序主窗口完全加载,它就会启动一个后台线程,该线程只调用 Assembly.Load()。当用户打开这个对话框时,加载这个 DLL 的小延迟就消失了。

【讨论】:

    【解决方案4】:
    var yourAppPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    Assembly.Load(Path.Combine(yourAppPath, "formAssembly.dll"));
    

    这样可以吗?

    【讨论】:

    • 这就是我所说的“弄乱路径和程序集名称”,所以不,它不会这样做
    • 只要程序集在同一个文件夹中,它将始终有效。所以我不认为这是一团糟。
    • 另外,它们不在同一个文件夹中
    猜你喜欢
    • 2012-01-10
    • 1970-01-01
    • 2011-10-14
    • 1970-01-01
    • 2012-10-15
    • 1970-01-01
    • 1970-01-01
    • 2023-04-03
    相关资源
    最近更新 更多