Unloading the Assembly loaded with Assembly.LoadFrom()

C#Garbage CollectionLoadGettype

C# Problem Overview


I need to check the time amount to run GetTypes() after loading the dll. The code is as follows.

Assembly assem = Assembly.LoadFrom(file);
sw = Stopwatch.StartNew();
var types1 = assem.GetTypes();
sw.Stop();
double time1 = sw.Elapsed.TotalMilliseconds;

I'd like to unload and reload the dll to check the time to spend in running GetTypes() again.

  • How can I unload it? assem = null is good enough?
  • Is there an explicit way to call garbage collector to reclaim the resource allocated to assem?

C# Solutions


Solution 1 - C#

Can you use another AppDomain?

AppDomain dom = AppDomain.CreateDomain("some");		
AssemblyName assemblyName = new AssemblyName();
assemblyName.CodeBase = pathToAssembly;
Assembly assembly = dom.Load(assemblyName);
Type [] types = assembly.GetTypes();
AppDomain.Unload(dom);

Solution 2 - C#

Instead of using LoadFrom() or LoadFile() you can use Load with File.ReadAllBytes(). With this it does not use the assembly file but will read it and use read data.

Your code will then look like

Assembly assem = Assembly.Load(File.ReadAllBytes(filePath));
sw = Stopwatch.StartNew();
var types1 = assem.GetTypes();
sw.Stop();
double time1 = sw.Elapsed.TotalMilliseconds;

From here We cannot unload the file unless all the domains contained by it are unloaded.

Hope this helps.:)

Solution 3 - C#

Unfortunately you can not unload an assembly once it is loaded. But you can unload an AppDomain. What you can do is to create a new AppDomain (AppDomain.CreateDomain(...) ), load the assembly into this appdomain to work with it, and then unload the AppDomain when needed. When unloading the AppDomain, all assemblies that have been loaded will be unloaded. (See reference)

To call the garbage collector, you can use

GC.Collect(); // collects all unused memory
GC.WaitForPendingFinalizers(); // wait until GC has finished its work
GC.Collect();

GC calls the finalizers in a background thread, that's why you have to wait and call Collect() again to make sure you deleted everything.

Solution 4 - C#

You can't unload assembly from the current AppDomain. But you can create new AppDomain, load assemblies into it, execute some code inside new AppDomain and then unload it. Check the following link: MSDN

Solution 5 - C#

If you only want to load the initial assembly without any of its dependent assemblies, you can use Assembly.LoadFile in an AppDomain, and then unload the AppDomain when done.

Create a loader class to load and work with the assembly:

class Loader : MarshalByRefObject
{
	public void Load(string file)
	{
		var assembly = Assembly.LoadFile(file);
		// Do stuff with the assembly.
	}
}

Run the loader in a separate app domain like this:

var domain = AppDomain.CreateDomain(nameof(Loader), AppDomain.CurrentDomain.Evidence, new AppDomainSetup { ApplicationBase = Path.GetDirectoryName(typeof(Loader).Assembly.Location) });
try {
	var loader = (Loader)domain.CreateInstanceAndUnwrap(typeof(Loader).Assembly.FullName, typeof(Loader).FullName);
	loader.Load(myFile);
} finally {
	AppDomain.Unload(domain);
}

Solution 6 - C#

Assembly cannot be unloaded unfortunately, and moreover - if you use appdomains - then it will prevent you to communicate with api's / assemblies of your main application.

Best description on problem can be found here:

Script Hosting Guideline http://www.csscript.net/help/Script_hosting_guideline_.html

If you want to run C# code without communication to your main application - then best approach is to integrate C# scripting API:

https://github.com/oleg-shilo/cs-script/tree/master/Source/deployment/samples/Hosting/Legacy%20Samples/CodeDOM/Modifying%20script%20without%20restart

And for integration you will need following packages:

C# script: http://www.csscript.net/CurrentRelease.html

Visual studio extension: https://marketplace.visualstudio.com/items?itemName=oleg-shilo.cs-script

If however you want to communicate from your C# script to your application - then using same appDomain with assembly name constantly changing is only way at the moment - but that unfortunately eats ram and disk space.

Code sample how to do it can be done - can be found from here:

https://github.com/tapika/cppscriptcore CsScriptHotReload.sln

And here is demo video:

https://drive.google.com/open?id=1jOECJj0_UPNdllwF4GWb5OMybWPc0PUV

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionprosseekView Question on Stackoverflow
Solution 1 - C#Rene de la garzaView Answer on Stackoverflow
Solution 2 - C#HardikView Answer on Stackoverflow
Solution 3 - C#slfanView Answer on Stackoverflow
Solution 4 - C#Yuriy RozhovetskiyView Answer on Stackoverflow
Solution 5 - C#Edward BreyView Answer on Stackoverflow
Solution 6 - C#TarmoPikaroView Answer on Stackoverflow