Je suis tombé sur cet article intéressant: How I Came to Love COM Interoperability on CodeProject, qui m'a fait réfléchir ...
L'auteur soutient qu'ils ne veulent pas de COM-ities dans leur bibliothèque .NET car cela enlève à la beauté de leur bibliothèque .NET. Au lieu de cela, ils préfèrent écrire une bibliothèque Interop distincte qui expose leur bibliothèque .NET à COM. Cette bibliothèque Interop gérerait le fait que COM ne prend pas en charge les constructeurs avec paramètres, méthodes surchargées, génériques, héritage, méthodes statiques, etc.
Et même si je pense que c'est très nouveau, cela ne complique-t-il pas simplement le projet?
- Vous devez maintenant tester à l'unité votre bibliothèque .NET ET une bibliothèque Interop.
- Vous devez maintenant passer du temps à découvrir comment contourner votre belle bibliothèque .NET et l'exposer à COM.
- Vous devez, effectivement, doubler ou tripler votre nombre de classes.
Je peux certainement comprendre si vous avez besoin de votre bibliothèque pour prendre en charge COM et non-COM. Cependant, si vous avez l'intention d'utiliser COM uniquement, ce type de conception apporte-t-il des avantages que je ne vois pas? Bénéficiez-vous uniquement des avantages du langage C #?
Ou, cela facilite-t-il la gestion des versions de votre bibliothèque en vous fournissant un wrapper? Est-ce que cela accélère l'exécution de vos tests unitaires en ne nécessitant pas l'utilisation de COM?
la source
Réponses:
Cet extrait de votre question est la partie la plus importante de votre décision de conception ici, et la réponse est (comme toujours) cela dépend .
Si vous avez uniquement l'intention d'utiliser la bibliothèque via COM Interop, vous devez concevoir l'ensemble du système dans cet esprit. Il n'y a aucune raison de tripler le nombre de lignes. Plus il y a de LoC dans le système, plus il aura de défauts. Vous devez donc concevoir votre système pour n'utiliser que des fonctionnalités compatibles COM.
Cependant , je ne peux pas penser à une bonne raison de restreindre l'utilisation d'une bibliothèque .Net à COM. Pourquoi ne voudriez- vous pas pouvoir utiliser l'assembly dans un autre code .Net? Cela n'a aucun sens de vous limiter de cette façon.
J'ai une certaine expérience avec cela, donc je vais partager comment je l'ai géré. Ce n'est certainement pas idéal. J'ai fait des compromis. J'utilise uniquement une façade pour les classes COM (interfaces vraiment) qui sont incompatibles avec les nouveaux idiomes .Net, sinon, j'expose directement l'interface .Net à COM. Cela signifie essentiellement que j'utilise une façade pour toute interface utilisant des génériques. Les génériques sont la seule chose que j'ai rencontrée qui sont tout simplement incompatibles. Malheureusement, cela signifie une façade pour tout ce qui renvoie un
IEnumerable<T>
, ce qui est assez courant.Cependant, ce n'est pas aussi mauvais qu'il n'y paraît, car votre classe de façade hérite de votre classe .Net et implémente une interface Interop spécifique. Quelque chose comme ça.
Cela maintient votre code en double à un minimum absolu et protège votre interface COM contre les modifications "non intentionnelles". Au fur et à mesure que votre classe principale / interface change, votre classe d'adaptateur doit remplacer d'autres méthodes (ou casser l'interface et augmenter le numéro de version principal). En revanche, tout votre code Interop n'est pas stocké dans l'
Interop
espace de noms, ce qui peut conduire à une organisation des fichiers déroutante. Comme je l'ai dit, c'est un compromis.Pour un exemple complet de cela, vous pouvez parcourir les dossiers SourceControl et Interop de mon référentiel.
ISourceControlProvider
etGitProvider
sera d'un intérêt particulier.la source
IEnumerable
à VBA? De plus, dans leRubberduck.Interop.GitProvider
pourquoi avez-vous défini des constructeurs paramétrés si COM ne les prend pas en charge?IEnumerable
COM via, mais il doit s'agir de la version non générique plus ancienne. Quant aux constructeurs, jetez un œil auSourceControlClassFactory
. Fondamentalement, vous le faîtes en initialisant une instance d'une classe qui n'a pas besoin de paramètres pour son ctor et en l'utilisant pour accéder à de nouvelles instances des classes de votre API.ComVisible(true)
classes / interfaces que COM ne prend pas en charge est simplement "ignoré"? Je suppose également que si vous avez une classe du même nom définie dans plusieurs espaces de noms, vous devrez fournir un uniqueProgId
si vous souhaitez exposer plusieurs d'entre eux?static
méthodes sont ignorées. J'essaie de voir s'il y a un équivalent de VB6VB_PredeclaredId
disponible. Je pense qu'il pourrait être possible de créer une instance par défaut.Cet auteur a besoin d'une gifle de réveil au visage. Pour tout projet professionnel, l'objectif est de créer des logiciels de travail que les gens souhaitent utiliser. Tout type d'idéaux malavisés sur la beauté vient bien après. Si tel est leur seul raisonnement, l'auteur a perdu toute crédibilité.
Pouvoir marquer vos classes comme com-visibles et pouvoir parler à votre code .NET via COM est extrêmement utile. Jeter ce grand avantage à la productivité pour la beauté est fou.
Cependant, faire fonctionner les choses avec COM nécessite des compromis, nécessitant un constructeur sans argument est l'un d'entre eux, et certaines des autres choses que vous avez mentionnées. Si ce sont des fonctionnalités que vous n'utilisez pas de toute façon, ou si cela ne vous fera pas de mal de ne pas les utiliser, alors il y a beaucoup de travail à enregistrer en utilisant la même classe pour COM et non com.
D'un autre côté, si vos clients COM attendent une interface radicalement différente, ont des dépendances ou d'autres limitations qui sont désagréables à gérer dans vos classes .NET, ou si vous vous attendez à changer considérablement vos classes .NET et devez maintenir COM en arrière- compatibilité, puis créez par tous les moyens une classe Interop pour combler cet écart.
Mais ne pensez pas à la "beauté". Être en mesure d'exposer COM via .NET est censé vous faire économiser du travail. Ne créez pas plus de travail pour vous-même.
la source
Set oObject = MyCOMInterop.NewMyClass()
passer de l'instanciation préalable d'un nouvel objet Factory?Eh bien, pour être juste, l'auteur original de cet article n'a utilisé le mot "beauté" nulle part dans son article, c'était vous, ce qui pourrait donner une impression biaisée à ceux qui n'ont pas pris le temps de lire l'article par se.
Pour autant que j'ai compris cet article, la bibliothèque .NET existait déjà et a été écrite sans COM à l'esprit - probablement parce qu'au moment où la bibliothèque a été créée, il n'était pas nécessaire de prendre en charge COM.
Plus tard, l'exigence supplémentaire de prise en charge de COM a été introduite. Face à une telle situation, vous avez deux options:
refonte de la lib originale pour la rendre compatible avec COM interop (avec le risque de casser des choses)
laissez la bibliothèque de travail d'origine la plupart du temps telle qu'elle est, et créez plutôt un assemblage séparé avec la fonction d'un "wrapper" (ou "adaptateur")
La création d'emballages ou d'adaptateurs est un modèle de conception bien connu (ou dans ce cas plus un modèle architectural), et les avantages et les inconvénients sont également bien connus. Un argument en est la meilleure "séparation des préoccupations", et cela n'a rien à voir avec la beauté.
À vos préoccupations
Lorsque vous introduisez votre interface COM dans votre bibliothèque .NET existante par refonte, vous devez tester cette interface non plus. L'introduction d'un adaptateur écrit manuellement peut nécessiter des tests supplémentaires sur le fonctionnement de l'interface, bien sûr, mais il n'est pas nécessaire de copier tous les tests unitaires de la fonctionnalité métier principale de la bibliothèque. N'oubliez pas que c'est juste une autre interface pour la lib.
Lorsque vous devez repenser la bibliothèque d'origine, vous devez également le comprendre, et je suppose que ce sera beaucoup plus de travail.
Uniquement pour les classes qui sont exposées via l'interface COM publique, qui devrait être un petit nombre de classes faisant partie de la bibliothèque d'origine.
Dit que, pour une situation différente que vous avez mentionnée, alors que vous savez déjà que vous devez prendre en charge COM en tant que citoyen de première classe dès le début, je pense que vous avez raison: il faut éviter d'avoir à ajouter une bibliothèque d'adaptateurs séparés et à concevoir le Lib .NET avec prise en charge COM directe.
la source