Me encontré con este interesante artículo: Cómo llegué a amar la interoperabilidad COM en CodeProject, que me hizo pensar ...
El autor argumenta que no quieren COM-ities en su biblioteca .NET porque les quita la belleza de su biblioteca .NET. En cambio, prefieren escribir una biblioteca Interop separada que exponga su biblioteca .NET a COM. Esta biblioteca de interoperabilidad manejaría el hecho de que COM no admite constructores con parámetros, métodos sobrecargados, genéricos, herencia, métodos estáticos, etc.
Y si bien creo que es muy novedoso, ¿no solo completa el proyecto?
- Ahora necesita probar su biblioteca .NET Y una biblioteca Interop.
- Ahora debe dedicar tiempo a descubrir cómo solucionar su hermosa biblioteca .NET y exponerla a COM.
- Necesita, efectivamente, duplicar o triplicar el recuento de clases.
Ciertamente puedo entender si necesita que su biblioteca sea compatible con COM y no COM. Sin embargo, si solo tiene la intención de usar COM, ¿este tipo de diseño trae algún beneficio que no veo? ¿Solo obtiene los beneficios del lenguaje C #?
¿O facilita el control de versiones de su biblioteca al proporcionarle un contenedor? ¿Hace que sus pruebas unitarias se ejecuten más rápido al no requerir el uso de COM?
fuente
Respuestas:
Este fragmento de su pregunta es la parte más importante de su decisión de diseño aquí, y la respuesta es (como siempre) depende .
Si solo tiene la intención de utilizar la biblioteca a través de COM Interop, debe diseñar todo el sistema teniendo esto en cuenta. No hay razón para triplicar el recuento de líneas. Mientras más LoC haya en el sistema, más defectos tendrá. Por lo tanto, debe diseñar su sistema para usar solo la funcionalidad compatible con COM.
Sin embargo , no puedo pensar en una buena razón para restringir el uso de una biblioteca .Net a COM. ¿Por qué no querrías poder usar el ensamblado en otro código .Net? Tiene poco sentido limitarse de esta manera.
Tengo algo de experiencia con esto, así que compartiré cómo lo he manejado. Ciertamente no es lo ideal. He hecho algunas compensaciones. Solo uso una fachada para las clases COM (interfaces realmente) que son incompatibles con los modismos .Net más nuevos, de lo contrario, expongo directamente la interfaz .Net a COM. Esto básicamente significa que uso una fachada para cualquier interfaz que use genéricos. Los genéricos son lo único que he encontrado que son simplemente incompatibles. Desafortunadamente, esto significa una fachada para todo lo que devuelve un
IEnumerable<T>
, que es bastante común.Sin embargo, esto no es tan malo como parece, porque su clase de fachada hereda de su clase .Net e implementa una interfaz Interop específica. Algo como esto.
Esto mantiene su código duplicado a un mínimo absoluto y protege su interfaz COM de cambios "no intencionales". A medida que su clase principal / interfaz cambia, su clase de adaptador tiene que anular más métodos (o romper la interfaz y cambiar el número de versión principal). Por otro lado, no todo su código de interoperabilidad se almacena en el
Interop
espacio de nombres, lo que puede llevar a una organización de archivos confusa. Como dije, es una compensación.Para un ejemplo completo de esto, puede navegar a través de las carpetas SourceControl e Interop de mi repositorio.
ISourceControlProvider
yGitProvider
será de particular interés.fuente
IEnumerable
a VBA? Además, enRubberduck.Interop.GitProvider
¿por qué definió constructores parametrizados si COM no los admite?IEnumerable
COM a través, pero tiene que ser la versión anterior, no genérica. En cuanto a los constructores, eche un vistazo aSourceControlClassFactory
. Básicamente, lo falsifica inicializando una instancia de una clase que no necesita parámetros para su ctor y usándola para obtener acceso a nuevas instancias de las clases de su API.ComVisible(true)
clases / interfaces que COM no admite simplemente se "ignora"? También supongo que si tiene una clase del mismo nombre definida en múltiples espacios de nombres, ¿tendría que proporcionar una únicaProgId
si desea exponer más de uno?static
métodos son ignorados. Estoy tratando de ver si hay un equivalente de VB6VB_PredeclaredId
disponible. Estoy pensando que podría ser posible crear una instancia predeterminada.Ese autor necesita una bofetada en la cara. Para cualquier proyecto profesional, el objetivo es hacer que el software funcione y que la gente quiera usar. Cualquier tipo de ideales equivocados sobre la belleza vienen mucho después de eso. Si ese es su único razonamiento, el autor ha perdido toda credibilidad.
Poder marcar sus clases como visibles y poder hablar con su código .NET a través de COM es enormemente útil. Descartar ese gran beneficio para la productividad de la belleza es una locura.
Sin embargo, hacer que las cosas funcionen con COM requiere algunas compensaciones, lo que requiere un constructor sin argumentos es una de ellas, y algunas de las otras cosas que mencionó. Si esas son características que no está utilizando de todos modos, o no le hará daño no usarlas, entonces hay mucho trabajo que guardar al usar la misma clase para COM y no com.
Por otro lado, si sus clientes COM esperan una interfaz dramáticamente diferente, tienen dependencias u otras limitaciones que son desagradables para tratar en sus clases .NET, o esperan cambiar significativamente sus clases .NET y necesitan mantener COM al revés. compatibilidad, entonces crea una clase de interoperabilidad para cerrar esa brecha.
Pero no pienses en la "belleza". Poder exponer COM a través de .NET está destinado a ahorrarle trabajo. No crees más trabajo para ti.
fuente
Set oObject = MyCOMInterop.NewMyClass()
sin tener que instanciar primero un nuevo objeto Factory?Bueno, para ser justos, el autor original de ese artículo no usó la palabra "belleza" en ninguna parte de su artículo, ese era usted, lo que podría dar una impresión parcial sobre eso para aquellos que no se tomaron el tiempo para leer el artículo. sí mismos.
Hasta donde he entendido ese artículo, la biblioteca .NET ya existía y se escribió sin COM en mente, probablemente porque en el momento en que se creó la biblioteca, no había ningún requisito para admitir COM.
Más tarde, se introdujo el requisito adicional de soportar COM. Ante tal situación, tiene dos opciones:
rediseñar la lib original para que sea compatible con la interoperabilidad COM (con el riesgo de romper cosas)
deje que la biblioteca de trabajo original esté como está, y cree un ensamblaje separado con la función de "envoltorio" (o "adaptador")
La creación de envoltorios o adaptadores es un patrón de diseño bien conocido (o en este caso más bien un patrón arquitectónico), y los pros y los contras también son bien conocidos. Un argumento a favor es la mejor "separación de preocupaciones", y eso no tiene nada que ver con la belleza.
A sus inquietudes
Cuando presenta su interfaz COM a su biblioteca .NET existente mediante el rediseño, también debe probar esa interfaz. La introducción de un adaptador escrito manualmente puede necesitar algunas pruebas adicionales de que la interfaz está funcionando, por supuesto, pero no es necesario copiar todas las pruebas unitarias de la funcionalidad comercial central de la lib. No olvides que es solo otra interfaz para la lib.
Cuando tienes que rediseñar la biblioteca original, también tienes que resolverlo, y supongo que será mucho más trabajo.
Solo para las clases que están expuestas a través de la interfaz COM pública, que debería ser un pequeño número de las clases que forman parte de la biblioteca original.
Dijo que, para una situación diferente que mencionó, cuando ya sabe que tiene que apoyar a COM como ciudadano de primera clase desde el principio, creo que está en lo correcto: uno debe evitar la molestia de agregar un adaptador separado lib y diseñar el .NET lib con soporte COM directamente.
fuente