12
votes

Traiter avec des dépendances facultatives (C #)

Nous avons une application qui s'intègre éventuellement à TFS, toutefois, car l'intégration est facultative, je ne veux évidemment pas que toutes les machines ont besoin d'assemblages TFS comme une exigence . .

Que dois-je faire?

  1. Est-il correct pour moi de faire référence aux bibliothèques TFS dans mes assemblées principales et assurez-vous simplement que je ne fais que référence aux objets liés à TFS lorsque j'utilise l'intégration TFS.
  2. Alternativement, l'option plus sûre serait de référencer les bibliothèques TFS dans un ensemble distinct "TFSWRAPPER":

    a. Est-ce que je suis alors correct pour moi de faire référence à cette assemblée directement (à nouveau aussi longtemps que je suis prudent de ce que j'appelle)

    b. Devrais-je plutôt expirer un ensemble d'interfaces pour mon ensemble Tfswrapper pour mettre en œuvre, puis instancier les objets à l'aide de la réflexion lorsque vous avez besoin.

    1 semble risqué pour moi, sur le côté retournement 2b semble sur-le-top - je construirais essentiellement un système de plug-in.

    Il doit sûrement être un moyen plus simple.


3 commentaires

"TFS" dans ce cas est "Système de fondation de l'équipe", n'est-ce pas?


Oui, mais je considère que la question est de moins en moins sur TFS et plus avec le meilleur moyen de référencer les assemblages qui pourraient ne pas être présents sur certains utilisateurs de machines.


D'Oh, je n'ai pas lu la première phrase avec précaution, donc je ne me suis donc pas réalisée par "facultatif" que vous vouliez dire "peut ne pas être présent sur la machine de l'utilisateur."


3 Réponses :


0
votes

Un concept "Plug-in" peut être la voie à suivre, et il peut également vous permettre (plus tard) étendre votre application pour travailler avec d'autres produits que TFS si nécessaire. L'option 2a sera tout aussi «risquée» (échec lorsque les fichiers liés sont manquants) comme option 1.

Vous pouvez faire un assemblage avec les interfaces requises pour votre objectif spécifique et référencer cet assemblage à partir de votre application et le "plug-in TFS". Ce dernier fournit ensuite des implémentations de vos interfaces et utilise TFS pour effectuer les opérations. L'application peut charger de manière dynamique un ensemble et créer des instances des types de plug-in nécessaires (via Activateur etc.) et jette ces instances à vos interfaces.

En fait, si vous faites ces types hériter de MarshalbyRef , vous pouvez même les charger dans un autre AppDomain et Faites donc une séparation propre de vos plugins et faites-les également décharmable.


2 commentaires

J'essaie effectivement de mettre en œuvre un système de plug-in. Cependant, parfois, j'aimerais utiliser un type introduit dans une autre assemblée. Le code utilisant ce type sera gardé avec une instruction "si" qui garantira que cela n'est utilisé que lorsque la bibliothèque est disponible et chargée. Y a-t-il un moyen de le faire en C #?


@Sergiybyelozyorov, oui, cela peut être fait, mais seulement par la liaison tardif (par exemple la réflexion ou la dynamique). Si le type peut implémenter une interface qui est toujours disponible, il le rendra plus pratique à utiliser.



6
votes

Le moyen le plus sûr (c'est-à-dire le moyen le plus simple de ne pas faire une erreur dans votre application) pourrait être le suivant.

Faire une interface qui résume votre utilisation de TFS, par exemple: P>

C:\github\TestReferences\TestReferences\TestReferences\bin\Debug>TestReferences.exe
2 Hello World!

C:\github\TestReferences\TestReferences\TestReferences\bin\Debug>TestReferences.exe 1

Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'OptionalLibrary, Version=1.0.0.0,
 Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
   at TestReferences.MainClass.foo()
   at TestReferences.MainClass.Main(String[] args) in C:\github\TestReferences\TestReferences\TestReferences\Program.cs:
line 11

C:\github\TestReferences\TestReferences\TestReferences\bin\Debug>


10 commentaires

Mais vous dites que c'est correct si la mise en œuvre de la classe TFS vit à l'intérieur du même assemblage?


À l'aide de l'API Windows traditionnel, si vous êtes un lien vers une DLL qui n'existe pas sur la machine d'utilisateur final, votre exécutable ne se charge pas du tout: et donc, à la place, vous devez utiliser Explicit LoadLibrary. Je ne suis pas certain que j'ai testé cela, mais je ne crois pas que ce soit vrai des références Dotnet aux assemblées qui n'existent pas sur la machine utilisateur finale ... et il est donc prudent d'avoir ces références dans votre Assemblage (il y aura une exception d'exécution uniquement lorsque / si vous essayez d'appeler l'assemblage inexistant).


Cela rendrait TFSFactory dépend de l'assemblage contenant de la classe TFS. Et puisque TFSFactory est utilisé dans l'application, il nécessitera toujours de distribuer le logiciel avec une DLL "en option" TFS. :-)


@Sergiybyelozyorov je crois (corrigez-moi si je me trompe) que vous avez besoin de la DLL afin de construire, mais que vous pouvez expédier / déployer sans elle ... et que s'il n'est pas présent sur la machine cible, l'Assemblée va toujours charger et que tout (à l'exception de la méthode TFSFactory) fonctionnera correctement.


@Chrisw: Nope. Je l'ai testé. Même si le code utilisant le TFSFactory n'exécute pas, l'application ne parvient toujours pas à fonctionner en raison d'une DLL manquante. P.s. J'ai testé cela avec mono, peut-être que c'est différent de .NET.


@Sergiybyelozyorov, je viens de le tester aussi (en utilisant .Net pas mono). L'application commence, mais je reçois une exception lorsque j'appelle une méthode dont la mise en œuvre dépend d'un type non défini. Cela devrait donc fonctionner si votre relevé si empêche la méthode appelée, et peut ne pas fonctionner si votre si Le protège-instruction est à l'intérieur de la méthode contenant du code qui dépend du type.


@Chrisw vient d'essayer cela avec VS2010. Même résultat que mono. Ce doit être quelque chose que je fais différemment de toi. Voici ma solution de test: dl.dropboxusercontent.com/16259710/testreferences.7z < / a>. Essayez de supprimer l'optionallibrary.dll à partir de dossier binaires et d'exécuter le programme. Cela ne devrait pas déclencher le code qui dépend de cette bibliothèque, qui n'est exécuté que lorsque "1" est transmis comme premier paramètre. Malgré cela, sur ma machine, il échoue toujours avec une exception FilenotFoundException.


@Sergiybyelozyorov Déplacez votre code dépendant de la conversation dans une méthode distincte. Comme ceci: Classe Mainclass {Public Static Void Main (String [] args) {Si (arg.Length> 0 && args [0] == "1" 1 ") {FOO (); } else {console.writine ("2 Hello World!"); }} Void statique FOO () {Talk Talk = Nouvelle conversation (); Console.writeline (Talk.Sayhello () + "" + Talk.Sayworld () + "!"); }}


@SergiybyElozyorov dans les résultats des tests indiqués ci-dessus, notez que l'exception ne provient pas de la ligne 1 de la méthode FOO ... elle vient de (essayer de JIT) la méthode FOO elle-même. Par conséquent, vous ne voulez pas ce code dans votre méthode principale.


@Chrisw Il était intéressant de savoir. En effet, une fois que le code dépendant est dans une méthode distincte, tout fonctionne très bien.



1
votes

1 commentaires

Cela semble assez intéressant, bien que peut-être un peu sur le dessus pour ce que je fais pour le moment! Je vais probablement jeter un coup d'oeil plus tard.