2017-10-10 7 views
0

il existe de nombreuses questions similaires, comme celui-ci. Mais ils ont tous des années et ne travaillent plus (aujourd'hui?). Donc voici ma question: Je veux charger un assemblage C# en mémoire et savoir s'il a des types inclus qui correspondent à une interface que je veux utiliser. Si l'assembly a ce type de classe inclus, je le référence et l'utilise dans mon application principale. Si ce n'est pas le cas, je veux décharger la DLL et ensuite pouvoir supprimer le fichier (de mon application principale ou à la main pendant que l'application est en cours d'exécution).chargement dynamique et le déchargement de l'assemblage C# dans appdomain

Ma première mise en œuvre a simplement ignoré l'approche appdomain, mais cela a fonctionné (sans supprimer ou remplacer les fichiers d'assemblage). Ensuite, j'ai essayé de charger les assemblages comme décrit dans divers exemples. Mais avec aucun j'ai été capable de supprimer les fichiers d'assemblage non nécessaires à partir du disque.

Soit il n'est tout simplement pas possible de décharger et de supprimer des assemblages lorsqu'ils ont été référencés dans une application ou que je fais quelque chose de mal. C'est ce que j'ai essayé enfin:

using System; 
using System.Diagnostics; 
using System.IO; 
using System.Reflection; 
using System.Runtime.CompilerServices; 
using System.Windows.Forms; 
using ESTLogViewer_V2.Formulare; 
using Parent; 
namespace ESTLogViewer_V2 
{ 
    static class Program 
    { 
     //<summary> 
     //Der Haupteinstiegspunkt für die Anwendung. 
     //</summary> 
     [STAThread] 
     static void Main() 
     { 
      LoadTest.Haupt(null); 
     } 
    } 
} 
namespace Parent 
{ 
    public class Constants 
    { 
     // adjust 
     public const string LIB_PATH = @"e:\PRJDOTNET4\ESTLogViewer V2\Plugins\LogFiles_Plugin.dll"; 
    } 

    public interface ILoader 
    { 
     string Execute(); 
    } 

    public class Loader : MarshalByRefObject, ILoader 
    { 
     public string Execute() 
     { 
      var assembly = Assembly.LoadFile(Constants.LIB_PATH); 
      foreach (var t in assembly.GetTypes()) 
      { 
       Debug.WriteLine(t.FullName); 

      } 
      return assembly.FullName; 
     } 
    } 

    class LoadTest 
    { 
     public static void Haupt(string[] args) 
     { 
      var domain = AppDomain.CreateDomain("child"); 
      var loader = (ILoader)domain.CreateInstanceAndUnwrap(typeof(Loader).Assembly.FullName, typeof(Loader).FullName); 
      Console.Out.WriteLine(loader.Execute()); 
      AppDomain.Unload(domain); 
      domain = null; 
      File.Delete(Constants.LIB_PATH); 
     } 
    } 
} 

Ainsi, ce code fonctionne jusqu'à ce que la déclaration File.Delete. Mais il jette une exception:

LogFiles_Plugin.clsSchritLogDateiSplitter 
LogFiles_Plugin.clsLogFileMeldDateiSplitter 
LogFiles_Plugin.clsLogFileMeldDateiSplitterNG 
LogFiles_Plugin.clsAuftragsAnalyseSplitter 
LogFiles_Plugin.clsAuftrag 
LogFiles_Plugin.clsS_R_SignalSplitter 
LogFiles_Plugin.clsLogFileGVMeldDateiSplitter 
LogFiles_Plugin.clsLogFileGVTeleSplitter 
LogFiles_Plugin.clsLogFileGVTeleSplitter+spalte 
<PrivateImplementationDetails>{37CEBF0C-E73A-4FE7-B152-9A858E6C176D} 
<PrivateImplementationDetails>{37CEBF0C-E73A-4FE7-B152-9A858E6C176D}+__StaticArrayInitTypeSize=6256 
"ESTLogViewer V2.exe" (Verwaltet (v4.0.30319)): "C:\Windows\Microsoft.Net\assembly\GAC_MSIL\mscorlib.resources\v4.0_4.0.0.0_de_b77a5c561934e089\mscorlib.resources.dll" geladen 
Eine Ausnahme (erste Chance) des Typs "System.UnauthorizedAccessException" ist in mscorlib.dll aufgetreten. 

En ce moment, en écrivant cette question, je l'ai fait d'autres tests - j'ai essayé de savoir pourquoi je ne pouvais pas supprimer le fichier d'assemblage. J'ai découvert qu'il était verrouillé par le débogueur distant de Visual Studio.

Donc la deuxième question est: Comment éviter le verrouillage du fichier avec le débogueur distant?

Répondre

2

J'ai trouvé que Assembly.LoadFile(...) verrouiller le fichier, même au-delà du déchargement de l'AppDomain.

Ma solution est d'abord charger l'ensemble d'octets dans la mémoire, puis le charger dans le AppDomain:

var assemblyBytes = System.IO.File.ReadAllBytes("myassembly.dll"); 
var assembly = System.Reflection.Assembly.Load(assemblyBytes); 

De cette façon, le fichier est jamais verrouillé et vous pouvez le supprimer, etc.

Il y a une meilleure réponse à une question similaire here.

+0

Bonjour @John, j'ai remplacé le code dans mon exemple par votre code et cela a fonctionné. Ceci est la solution pour l'approche "appdomain". Mais cela devrait fonctionner sans utiliser l'appdomain non plus. –

+0

@WolfgangRoth Bien que cela fonctionne pour les deux, notez que (comme l'indique la [réponse liée] (https://stackoverflow.com/a/18935973/3181933), vous ne pouvez pas décharger l'assemblage une fois qu'il a été chargé sauf C'est dans un AppDomain. [MSDN est d'accord] (https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/assemblies-gac/how-to-load-and-unload-assemblies) – john

+0

Je ne l'ai pas encore fait étudier les effets des multiples chargements de l'assemblage. Mais ma première idée du chargement de l'assemblage était de pouvoir implémenter des plugins dans mon code qui peuvent être échangés par l'utilisateur. Et chaque fois que l'utilisateur met à jour la liste des plugins, de nouveaux devraient être ajoutés et les plus anciens devraient être supprimés de la liste montrée à l'utilisateur - il se peut que l'application ne puisse remplacer des assemblages qui diffèrent seulement par la mise en œuvre. otherwhise a le même espace de nommage et les mêmes noms ... J'essaierai peut-être cela demain. –