web-dev-qa-db-fra.com

Intégration d'ensembles dans un autre ensemble

Si vous créez une bibliothèque de classes qui utilise des éléments d'autres assemblys, est-il possible d'incorporer ces autres assemblys dans la bibliothèque de classes en tant que ressource?

C'est à dire. au lieu d'avoir MyAssembly.dll , SomeAssembly1.dll et SomeAssembly2.dll assis sur le système de fichiers, ces deux autres fichiers sont regroupés dans MyAssembly.dll et sont utilisables dans son code.


Je suis aussi un peu confus sur la raison pour laquelle les assemblys .NET sont des fichiers .dll . Ce format n'existait-il pas avant .NET? Les assemblys .NET sont-ils tous des DLL, mais ne sont-ils pas tous des assemblys .NET? Pourquoi utilisent-ils le même format de fichier et/ou la même extension de fichier?

39
xyz

RegardezILMergepour la fusion des assemblys.

Je suis aussi un peu confus sur la raison pour laquelle les assemblys .NET sont des fichiers .dll. Ce format n'existait-il pas avant .NET? 

Oui.

Sont tous les DLL d'assemblées .NET, 

Les DLL ou EXE normalement - mais peut aussi être netmodule.

mais toutes les DLL ne sont pas des assemblys .NET? 

Correct.

Pourquoi utilisent-ils le même format de fichier et/ou la même extension de fichier?

Pourquoi devrait-il en être autrement - cela sert le même but!

35
AtliB

ILMerge fusionne des assemblages, ce qui est agréable, mais parfois pas tout à fait ce que vous voulez. Par exemple, lorsque l'Assemblée en question est une Assemblée à nom fort et que vous n'en avez pas la clé, vous ne pouvez pas exécuter ILMerge sans rompre cette signature. Ce qui signifie que vous devez déployer plusieurs assemblys. 

Comme alternative à ilmerge, vous pouvez incorporer un ou plusieurs assemblys en tant que ressources dans votre fichier EXE ou DLL. Ensuite, lors de l'exécution, lors du chargement des assemblys, vous pouvez extraire l'assembly incorporé par programmation, puis le charger et l'exécuter. Cela semble compliqué, mais il y a juste un peu de code standard. 

Pour ce faire, incorporez un assemblage, de la même manière que n'importe quelle autre ressource (image, fichier de traduction, données, etc.). Ensuite, configurez un AssemblyResolver qui est appelé à l'exécution. Il doit être configuré dans le constructeur statique de la classe de démarrage. Le code est très simple. 

    static NameOfStartupClassHere()
    {
        AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(Resolver);
    }

    static System.Reflection.Assembly Resolver(object sender, ResolveEventArgs args)
    {
        Assembly a1 = Assembly.GetExecutingAssembly();
        Stream s = a1.GetManifestResourceStream(args.Name);
        byte[] block = new byte[s.Length];
        s.Read(block, 0, block.Length);
        Assembly a2 = Assembly.Load(block);
        return a2;
    }

La propriété Name du paramètre ResolveEventArgs est le nom de l'assembly à résoudre. Ce nom fait référence à la ressource, pas au nom de fichier. Si vous intégrez le fichier nommé "MyAssembly.dll" et appelez la ressource incorporée "Foo", le nom que vous souhaitez ici est "Foo". Mais ce serait déroutant, donc je suggère d'utiliser le nom de fichier de l'Assemblée pour le nom de la ressource. Si vous avez incorporé et nommé votre assembly correctement, vous pouvez simplement appeler GetManifestResourceStream () avec le nom de l'assembly et charger l'assembly de cette façon. Très simple. 

Cela fonctionne avec plusieurs assemblages, aussi bien qu'avec un seul assemblage intégré. 

Dans une vraie application, vous voudrez une meilleure gestion des erreurs dans cette routine - comme par exemple s'il n'y a pas de flux portant le même nom? Que se passe-t-il si la lecture échoue? etc. Mais il vous reste à faire. 

Dans le reste du code de l'application, vous utilisez des types de l'assembly comme d'habitude. 

Lorsque vous créez l'application, vous devez ajouter une référence à l'Assemblée en question, comme vous le feriez normalement. Si vous utilisez les outils de ligne de commande, utilisez l'option/r dans csc.exe; si vous utilisez Visual Studio, vous devez "Ajouter une référence ..." dans le menu contextuel du projet.

Au moment de l'exécution, la vérification et la vérification de version d'Assembly fonctionnent normalement. 

La seule différence est dans la distribution. Lorsque vous déployez ou distribuez votre application, vous n'avez pas besoin de distribuer le DLL pour l'assembly incorporé (et référencé). Il suffit de déployer l'Assemblée principale; il n'est pas nécessaire de distribuer les autres assemblys car ils sont incorporés dans le fichier principal DLL ou EXE. 

55
Cheeso

Vous pouvez incorporer un assemblage (ou n'importe quel fichier, en fait) en tant que ressource (puis utilisez la classe ResourceManager pour y accéder), mais si vous souhaitez simplement combiner des assemblys, vous feriez mieux d'utiliser un outil. comme ILMerge .

Les fichiers EXE et DLL sont Les exécutables portables de Windows , sont suffisamment génériques pour prendre en charge les types de code futurs, y compris tout code .NET (ils peuvent également être exécutés sous DOS mais en affichant uniquement un message ne sont pas censés fonctionner sous DOS). Ils incluent des instructions pour lancer le runtime .NET s'il n'est pas déjà en cours d'exécution. Il est également possible qu'un seul assemblage couvre plusieurs fichiers, bien que ce ne soit presque jamais le cas.

7
Mark Cidade

Remarque ILMerge ne fonctionne pas avec des ressources intégrées telles que XAML. Par conséquent, les applications WPF, etc., devront utiliser la méthode de Cheeso.

5
Richard Dingwall

Il y a aussi l'utilitaire mkbundle proposé par le projet Mono

4
hova

Pourquoi utilisent-ils le même format de fichier et/ou la même extension de fichier?

Pourquoi devrait-il en être autrement - cela sert le même but!

Mon éclaircissement de 2 ¢: DLL est une bibliothèque de liens dynamiques. L’ancien style .dll (code C) et .net style .dll sont par définition des bibliothèques de "liens dynamiques". Donc. Dll est une description appropriée pour les deux.

1
Eric

Je vous suggère d'essayer Costura.Fody . N'oubliez pas d'installer Package-Fody avant Costura.Fody (afin d'obtenir le dernier Fody!)

0

En ce qui concerne la réponse de Cheeso consistant à incorporer les assemblys en tant que ressources et à les charger dynamiquement à l’aide de la surcharge Load (byte []) à l’aide d’un gestionnaire d’événement AssemblyResolve, vous devez modifier le résolveur de renvoie l'instance d'assemblage existante si elle est déjà chargée. 

Les assemblys chargés à l'aide de cette surcharge n'ont pas de contexte, ce qui peut amener le framework à essayer de recharger l'assembly plusieurs fois. Sans renvoyer une instance déjà chargée, vous pouvez vous retrouver avec plusieurs instances du même code d'assembly et de types identiques, mais ne le seront pas, car la structure les considère comme provenant de deux assemblys différents.

Au moins une façon de créer plusieurs événements AssemblyResolve pour le même assembly chargé dans le "Aucun contexte" consiste à faire référence à des types exposés dans plusieurs assemblys chargés dans votre AppDomain, au moment de l'exécution du code nécessitant la résolution de ces types.

https://msdn.Microsoft.com/en-us/library/dd153782%28v=vs.110%29.aspx

Quelques points saillants du lien:

"Les autres assemblys ne peuvent pas être liés à des assemblys chargés sans contexte, à moins que vous ne gériez l'événement AppDomain.AssemblyResolve"

"Le chargement de plusieurs assemblys avec la même identité sans contexte peut entraîner des problèmes d'identité de type similaires à ceux causés par le chargement d'assemblys avec la même identité dans plusieurs contextes. Voir Eviter le chargement d'un assemblage dans plusieurs contextes."

0
user3447701