webentwicklung-frage-antwort-db.com.de

Entladen der mit Assembly.LoadFrom () geladenen Assembly

Ich muss den Zeitbetrag überprüfen, um GetTypes () auszuführen, nachdem die DLL geladen wurde. Der Code lautet wie folgt.

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

Ich möchte die DLL entladen und erneut laden, um zu überprüfen, wie viel Zeit GetTypes () erneut benötigt.

  • Wie kann ich es entladen? assem = null ist gut genug? 
  • Gibt es eine explizite Möglichkeit, den Garbage Collector anzurufen, um die dem Assem zugewiesene Ressource zurückzufordern?
46
prosseek

Leider können Sie eine Assembly nicht entladen, sobald sie geladen ist. Sie können jedoch eine AppDomain entfernen. Sie können eine neue AppDomain (AppDomain.CreateDomain (...)) erstellen, die Assembly in diese Appdomain laden, um mit ihr zu arbeiten, und die AppDomain dann entladen, wenn dies erforderlich ist. Beim Entladen der AppDomain werden alle geladenen Assemblys entladen. (Siehe reference )

Um den Garbage Collector anzurufen, können Sie verwenden 

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

GC ruft die Finalizer in einem Hintergrundthread auf. Deshalb müssen Sie warten und Collect () erneut aufrufen, um sicherzustellen, dass Sie alles gelöscht haben.

32
slfan

Können Sie eine andere AppDomain verwenden?

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

Anstelle von LoadFrom() oder LoadFile() können Sie Load mit File.ReadAllBytes() verwenden. Dabei wird die Assembly-Datei nicht verwendet, sondern wird gelesen und Lesedaten verwendet.

Ihr Code wird dann aussehen

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

Von hier Wir können die Datei nicht entladen, wenn nicht alle darin enthaltenen Domänen entladen sind.

Hoffe das hilft.:)

30
Hardik

Sie können Assembly nicht von der aktuellen AppDomain entfernen. Sie können jedoch eine neue AppDomain erstellen, Assemblys darin laden, Code in der neuen AppDomain ausführen und dann entladen. Überprüfen Sie den folgenden Link: MSDN

4

Assembly kann leider nicht entladen werden. Außerdem werden Sie - wenn Sie Appdomains verwenden - verhindern, dass Sie mit Apis/Assemblys Ihrer Hauptanwendung kommunizieren.

Die beste Problembeschreibung finden Sie hier:

Skript-Hosting-Richtlinie http://www.csscript.net/help/Script_hosting_guideline_.html

Wenn Sie C # -Code ohne Kommunikation mit Ihrer Hauptanwendung ausführen möchten, sollten Sie die C # -Skripting-API integrieren:

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

Und für die Integration benötigen Sie folgende Pakete:

C # -Skript: http://www.csscript.net/CurrentRelease.html

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

Wenn Sie jedoch von Ihrem C # -Skript zu Ihrer Anwendung kommunizieren möchten, ist die Verwendung derselben appDomain mit sich ständig änderndem Assembly-Namen im Moment nur eine Möglichkeit - aber das frisst leider RAM- und Festplattenspeicherplatz.

Codebeispiel, wie es gemacht wird, kann gemacht werden - kann hier gefunden werden:

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

Und hier ist ein Demo-Video:

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

0
TarmoPikaro

Wenn Sie nur die ursprüngliche Assembly ohne eine der abhängigen Assemblys laden möchten, können Sie Assembly.LoadFile in einer AppDomain und entladen Sie die AppDomain, wenn Sie fertig sind.

Erstellen Sie eine Loader-Klasse zum Laden und Arbeiten mit der Assembly:

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

Führen Sie den Loader in einer separaten App-Domain wie folgt aus:

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);
}
0
Edward Brey