25

In my app I need to show a form on mouse click. The problem is that the form is in another assembly and because of lazy nature of assembly loading it is likely that the assembly isn't loaded yet when the mouse button is pressed. So what I have is very noticeable pause before the form finally appears.

I was able to come up with a dumb fix by calling new FormFromAnotherAssembly() in my initialization method. That, of course, took care of things and the pause is no longer there, but it's very ugly. The only thing I like about this solution is that I don't have to mess with paths and assembly names which I have to do if I want to use something like Assembly.Load.

So, what's the good, robust solution of choice if I want to make sure the assembly is loaded before I actually need it?

Thanks in advance.

Dyppl
  • 12,161
  • 9
  • 47
  • 68
  • You are dismissing a good solution. The only other one is to get a faster hard drive. If you haven't defragged the disk in the past 6 months then now is a good time. – Hans Passant Feb 04 '11 at 09:16

4 Answers4

23

Explicit pre-load in your init is probably still your best option.

a typeof(SomeTypeFromAnotherAssembly) should be enough - along with some opaque method that can't be optimised away; perhaps:

GC.KeepAlive(typeof(SomeTypeFromAnotherAssembly));

This avoids the new. Note that this will be loaded, but not JITted etc.

If you wanted, you could do it on a BG thread:

private static void LoadSomeStuff(object state) {
    GC.KeepAlive(typeof(SomeTypeFromAnotherAssembly));
}
...
ThreadPool.QueueUserWorkItem(LoadSomeStuff);
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Thank you Marc, but what if I want it loaded AND JITted etc? Because it looks like loading an assembly is only part of the problem and the pause is still there. – Dyppl Feb 04 '11 at 08:19
  • @Dyppl - JIT is relatively quick - I suggest the issue is loading *other* (downstream) assemblies and loading other resources. If you debug you should be able to see what else loads... – Marc Gravell Feb 04 '11 at 08:22
  • Well, yes, unfortunately, the form is a WPF one and drags a lot of crap along with it. – Dyppl Feb 04 '11 at 08:24
  • @Dyppl then you may have no choice to spin up a form to prep everything; and you should probably only do that from the UI thread. – Marc Gravell Feb 04 '11 at 09:02
  • thanks, I don't know what what I'll end up doing, but your solution was good for the task I described in question, so I'm marking it – Dyppl Feb 04 '11 at 09:30
  • Nice solution. Does not work for me with "official" GAC assemblies. Actually.. what I want is the "xxx loaded" message in the Debug Output window in VS, it does not appear for GC.KeepAlive(typeof(System.Runtime.Remoting.RemotingServices)); (to load System.Runtime.Remoting.dll) – Andreas Reiff Jul 06 '12 at 10:33
  • I think this may achieve the same thing while being slightly more readable: http://stackoverflow.com/a/4181676/1688738 (I'm not sure if this depends on you having written a static initializer but somehow I doubt it does). – Hugh W Feb 07 '13 at 18:12
  • @MarcGravell I think you can spin up a second STA thread to load the form in the background, with the window state as hidden. – fjch1997 Jan 19 '21 at 21:58
2

I think that the easiest way is to just use the assembly name in Assembly.Load():

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

You can find the assembly name under the reference properties in Visual studio:

assembly name in visual studio

This way you can avoid entering dll file paths etc. I use this to speed up the loading of a dialog that uses this DLL. As soon as the program main window is fully loaded it launches a background thread that just calls Assembly.Load(). When the user opens this dialog the small lag of loading this DLL is gone.

carlos357
  • 449
  • 5
  • 9
2

I believe that Assembly.Load is the way.

During application startup you should locate modules, plug-ins or any other run-time pluggable and load their assemblies into application's domain (AppDomain).

Or another and better option: Why don't you use inversion of control for that?

You can use Castle Windsor for that. Let's say you've 4 forms to load in run-time, so, you can create 4 components of Form class which their implementation are the 4 forms to load during the life-cycle of your program.

How to pre-load with this approach? You simply resolve all dependencies/components that are of type of Form and you got it:

container.ResolveAll<Form>();

Later you'll get a particular form:

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

If you don't know inversion of control, comment out and I'll assist you, no problem! :)

Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206
  • Well, think if you're going to have lots of run-time loaded forms. If this isn't the situation, yes, this is overkill for you. – Matías Fidemraizer Feb 04 '11 at 08:19
  • Well, at the moment it's unlikely, but thank you anyway, I'll try your solution when I have the need. – Dyppl Feb 04 '11 at 08:22
  • BTW, why don't you do a hand-made inversion of control, something as simple as put in your application settings the full assembly qualified name of your form, and just do something like YourForm.Preload() - returning the form - which would do Type.GetType(Properties.Settings.Default.FormAssemblyName); ? (that would mean other form's assembly is in the bin directory, but if this isn't your case, just provide the full physical path in settings, and just do an Assembly.Load in your SomeForm.Preload()) – Matías Fidemraizer Feb 04 '11 at 08:24
  • I was hoping for a more elegant solution. Why would I go through all this if the framework knows where to find the form and how to load it? It just doesn't do it until he really needs to, so I wanted to make him need it a little sooner. Of course, I can do all this, but the question was more or less "is there a better way to do it". – Dyppl Feb 04 '11 at 08:30
  • Can you clarify if this form assembly is referenced? Or it's just placed in the bin directory? – Matías Fidemraizer Feb 04 '11 at 08:45
  • 1
    oh, then, maybe you've another simple option: Asssembly.GetReferencedAssemblies. This method returns all referenced assemblies by one. That's you can automatically pre-load all referenced assemblies as your application start invoking Assembly.Load(AssemblyName). It's almost the same thing, but you avoid literals, because app assembly will be retrieved with Assembly.GetExecutingAssembly. – Matías Fidemraizer Feb 04 '11 at 12:09
1
var yourAppPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
Assembly.Load(Path.Combine(yourAppPath, "formAssembly.dll"));

Will that do?

jgauffin
  • 99,844
  • 45
  • 235
  • 372