3

I do not want to dynamic load libraries via code.

I want to do something like follows:

//first assembly
public void Go()
{
    //second assembly does not loaded yet
    var s = new TestItem(); //at this point second assembly will be loaded before calling the constructor
}

//second assembly
public class TestItem
{
    public TestItem()
    {

    }
}

i.e. I want to load referenced libraries only when a member from it's assembly will be called. Is it possible? And if it is possible - how can I do this?

Mikhail Tulubaev
  • 4,141
  • 19
  • 31
  • Don't believe that's possible without having some kind of wrapper class that you called that loaded the dll when you first call into it - see [shim](http://stackoverflow.com/questions/2116142/what-is-a-shim) – auburg Apr 13 '16 at 10:09
  • 1
    Maybe the Managed Extensibility Framework (MEF) and its lazy loading feature can help you, if I understand you correctly. – BHuelse Apr 13 '16 at 10:12
  • 2
    Assemblies *are* loaded dynamically. But the loading happens just a stage earlier than you expect - because the system needs to load the assembly when it's *compiling* a method that consumes a type from the assembly. (Or when it's accessing a type that uses a dependent type as a base class or implementing an interface) – Damien_The_Unbeliever Apr 13 '16 at 10:16
  • @Damien_The_Unbeliever is right. References assemblies don't have to present every time. They are only loaded when the Type/Method that uses a type(Field/Property/MethodArgument) from the other assembly is used. – Toxantron Apr 13 '16 at 10:22
  • @Damien_The_Unbeliever so, answer for my question is "No". Well, can I force the project to compile referenced assembly during runtime? – Mikhail Tulubaev Apr 13 '16 at 10:24

1 Answers1

3

As Damien_The_Unbeliever already pointed out in the comments assemblies are loaded dynamically whenever a type from it is used. Depending on where a type is used this happens when a Type is loaded (Properties, Fields, MethodParameters ...) or when a method is invoked (local variables, static calls).

In your example if you really want to load another assembly based on a condition I suggest to place it in another method. This way the other assembly is only loaded when GoDeep() is called.

//first assembly
public void Go()
{
    if (condition)
        GoDeep();
}
[MethodImpl(Met‌​hodImplOptions.NoInlining)]
private void GoDeep()
{
    var s = new TestItem(); //at this point second assembly will be loaded 
}

Fun fact: This the reason that FileNotFoundExceptions are not thrown at application startup but sometimes maybe days later when the user finally clicked a button that would have used the missing file.

Edit: To make sure the method is not inlined in Release this was added for the JIT. I want to add I would not use this approach at all because it is, to say the least, risky and may cause application failure.

Toxantron
  • 2,218
  • 12
  • 23
  • As far as i understand, Damien wrote, that assembly wiil be load when method, which calling another assembly, is compiling. So, in your example another assembly will be load, when GoDeep is compiling, not calling. Correct me, if I do not right – Mikhail Tulubaev Apr 13 '16 at 10:32
  • 1
    When he said *compiling* he was refering to the JIT compiler which in turn is called the moment a method is used for the first time. Hence the name **J**ust**I**n**T**ime Compiler. – Toxantron Apr 13 '16 at 10:35
  • More likely this method won't work on release mode, since the `GoDeep` method is a good candidate for inlining (and thus will be completely removed and the call substituted by its contents)... you can decorate that `GoDeep` method with `[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]` to prevent that – Jcl Apr 13 '16 at 10:38
  • @Jcl yes you are right. Took the liberty of adding your suggestion. – Toxantron Apr 13 '16 at 10:53
  • well, thanks, I have understood that I have not realised full lifecycle of compilation – Mikhail Tulubaev Apr 13 '16 at 11:00