Je m'excuse d'avance si le titre n'a pas de sens. Je suis très novice dans le domaine des applications et du chargement d'assemblages et je ne sais pas vraiment comment dire ce que j'essaie de demander.Pourquoi Assembly.Load ne semble-t-il pas affecter le thread en cours lors de la résolution de références (pas par réflexion)?
J'ai essayé de charger des DLL incorporées dans une application pendant l'exécution et je n'arrive pas à comprendre pourquoi cela fonctionne dans un sens mais pas dans l'autre. Il semble que si vous essayez de charger des DLL (à partir d'un tableau d'octets) dans le domaine actuel, tous les objets/threads créés après cela seront capables de résoudre les références sur la bibliothèque nouvellement chargée, mais les objets dans le contexte d'origine ne seront pas résolus. bibliothèque nouvellement chargée.
Voici mon exemple de bibliothèque qui sera chargée à partir comme une ressource intégrée lors de l'exécution (nécessite une référence à la WPF PresentationFramework.dll pour MessageBox):
namespace LoaderLibrary
{
public class LoaderLibrary
{
public static void Test()
{
System.Windows.MessageBox.Show("success");
}
}
}
Dans mon application console .csproj I ajouter manuellement les éléments suivants ressource incorporée pour ce projet et comprennent une référence de projet à LoaderLibrary ainsi:
<ItemGroup>
<EmbeddedResource Include="..\LoaderLibrary\bin\$(Configuration)\LoaderLibrary.dll">
<LogicalName>EmbeddedResource.LoaderLibrary.dll</LogicalName>
</EmbeddedResource>
</ItemGroup>
Voici la co de mon application console qui charge cette bibliothèque (nécessite une référence de projet au LoaderLibrary csproj) AUSSI: Nécessité de mettre CopyLocal à faux pour référence LoaderLibrary:
Ce code est en mesure pour charger et exécuter la fonction LoaderLibrary.LoaderLibrary.Test().
Ma question est pourquoi ce qui suit ne fonctionne pas?
static void Main(string[] args)
{
EmbeddedAssembly.Load("EmbeddedResource.LoaderLibrary.dll");
System.AppDomain.CurrentDomain.AssemblyResolve += (s, a) => { return EmbeddedAssembly.Get(a.Name); };
LoaderLibrary.LoaderLibrary.Test(); // very unhappy line of code
}
Cela ne fonctionne pas non plus:
static void Main(string[] args)
{
EmbeddedAssembly.Load("EmbeddedResource.LoaderLibrary.dll");
System.AppDomain.CurrentDomain.AssemblyResolve += (s, a) => { return EmbeddedAssembly.Get(a.Name); };
var app = new TestApp();
LoaderLibrary.LoaderLibrary.Test(); // very unhappy line of code
}
Les assemblys sont chargés par le compilateur juste-à-temps. Il doit convertir votre méthode Main() en code machine avant de pouvoir démarrer. Cela arrive bien sûr * avant * qu'il ne fonctionne, donc AssemblyResolve ne peut rien faire pour aider à trouver l'assembly. Plus mal dans la version Release, l'optimiseur regarde vers l'avenir pour trouver des opportunités pour les méthodes en ligne. Vous avez besoin d'une autre méthode, par exemple RealMain(), déplacez l'appel Test() dans cette méthode. Et donnez-lui l'attribut [MethodImpl (MethodImplOptions.Nolinling)] pour ralentir l'optimiseur. –
Donc, fondamentalement, il prend n'importe quelle fonction est le point d'entrée et le convertit en IL avant d'essayer d'exécuter du code? Et puisque l'assemblage n'a pas été techniquement ajouté à l'AppDomain, il en résulte une résolution de dépendance échouée? –
Ok, je suis presque sûr de le comprendre maintenant. Fondamentalement, lors de la compilation JIT du point d'entrée, il ne parvient pas à résoudre la dépendance car il ne peut évidemment exécuter aucun code avant de le compiler, ce qui entraîne l'erreur que je voyais. Déplacer les appels vers les assemblys chargés dynamiquement dans une portée de fonction différente et marquer les méthodes qui les appellent avec [MethodImpl (MethodImplOptions.Nolinling)] permet d'empêcher l'optimiseur de déplacer le code qui référence les assemblys chargés dynamiquement dans une portée cela serait compilé avant le chargement de l'assemblage. –