2010-07-03 10 views
14

Esto probablemente suena como una pregunta estúpida, pero voy a intentarlo de todos modos.¿Es posible habilitar dependencias circulares en Visual Studio en el nivel de ensamblaje? ¿Las asambleas mutuamente dependientes serían posibles?

Así en Visual Studio, no se puede tener dos proyectos de X e Y tal que X hace referencia a Y e Y referencias X.

En general, puedo totalmente entender cómo tener una dependencia circular puede ser problemático, por una variedad de razones

¿Pero realmente no es posible para compilar dos proyectos que son interdependientes de esta manera? Me parece que debe ser posible, ya que (en mi opinión, tal vez soy completamente off-base sobre esto) tener dos ensambles mutuamente dependientes realmente no es entonces diferente de tener dos clases mutuamente dependientes - un caso que es legal y puede compilarse.

Tendría sentido para mí si dijera: "dos conjuntos no pueden depender el uno del otro porque el compilador no pudo compilar uno antes que el otro"; excepto que parece que podrías hacer el mismo argumento para dos clases dentro del mismo ensamblado, y claramente el compilador puede manejar este escenario muy bien.

Básicamente, la razón por la que estoy preguntando no es que tenga un deseo desesperado de hacer esto que, de todos modos, sé que es poco aconsejable. Específicamente, me pregunto porque sería bueno si pudiera tener dos proyectos, por ejemplo, MyProjectCS y MyProjectVB, que existían básicamente como dos partes mutuamente dependientes de una sola unidad, y solo estaban separados porque ciertas partes estaban escritas en C# y otras partes fueron escritas en VB.NET.

lo tanto, mi pregunta es (uff, tres veces):

  1. ¿Es posible habilitar este comportamiento (en Visual Studio, o en otra parte, para el caso)?
  2. Si no es posible dentro de ningún IDE, ¿es posible al menos teóricamente, o podrían no existir conjuntos mutuamente dependientes?
  3. Si ni siquiera es teóricamente posible, ¿por qué no? En otras palabras, ¿cómo se diferencian los conjuntos mutuamente dependientes del código mutuamente dependiente dentro de un único conjunto?
+7

Esto me pasa todo el tiempo ... mi proyecto Egg lanza 'Chicken.dll no encontrado ...' mientras mi proyecto Chicken arroja un error similar. Ho-Hum. –

+2

El .NET framework internamente usa ensambles mutuamente dependientes. Alguien lo descubrió hace un tiempo después de desmontar los ensamblados de .NET y planteó esa pregunta en SO (aunque no puede encontrar el enlace). – Alex

+0

@Alex, sí lo encontré una vez. Me pareció que lo hizo a través de la reflexión. – Joshua

Respuesta

11

no sé cómo hacerlo en un IDE; sin embargo, es posible construirlo a través de un proceso de construcción compilado.

Necesitará:

  1. Asamblea Un
  2. Asamblea B
  3. Asamblea del trozo B

donde Trozo Asamblea B contiene las clases públicas y métodos públicos de la Asamblea B y el mismo AssemblyInfo. * Y hace referencia a la misma clave pública.

fin

Cuerpo:

  1. Compilar Asamblea del trozo B
  2. Copia Asamblea del trozo B para el directorio de salida de la Asamblea B
  3. montaje
  4. Build
  5. ensamble estructura B

Aviso que no puede tener referencias de bucle directo de los tipos en las firmas de método; sin embargo, puede tener bucles efectivos al lanzar objetos.

NOTA:

ilasm puede compilar verdaderos montajes mutuamente recursivos que de alguna manera se puede resolver tipos que no existen en tiempo de compilación.

ADICIONAL:

la aspnet_compiler parece ser capaz de mezclar diferentes idiomas en un mismo proyecto (quién sabe cómo).

+3

Puede tener bucles en los tipos de las firmas de métodos usando un proceso de compilación aún más complicado: primero defina todas las clases y compile eso, luego configure la jerarquía de herencia (usando los resguardos del paso anterior) y agregue todos los métodos que no reemplacen (pero sin cuerpos), y en un tercer paso finalmente hacer una compilación normal (ahora finalmente incluye cuerpos de método). Si realmente quieres hacer esto, #if será tu nuevo mejor amigo. – Daniel

+0

wow Daniel Nunca pensé en eso. – Joshua

2

No sé cómo funcionaría en VB, pero teóricamente debería ser posible usar algún tipo de marcador de posición apuntando al otro (generando código ilegal) para compilar uno de ellos, y luego usar eso para compilar el otro, y luego recompilar el primero.

Así es como, por ejemplo, la resolución de dependencia circular funciona al compilar programas que se requieren mutuamente.

--aunque por lo general que ha hecho mediante la desactivación de las características que aún no existen

+3

Para su información, en C y C++ nativos logramos esto en virtud de los archivos de encabezado. – Joshua

+0

@Joshua, esto funciona si ambas cosas interdependientes se compilan y se vinculan al mismo tiempo. La descripción de la respuesta de "deshabilitar las características que aún no existen" se utiliza a menudo para romper ciclos a nivel de paquete con la ayuda de un administrador de paquetes. – binki

+0

Hmmm mi administrador de paquetes puede manejar dependencias cíclicas. – Joshua

6

Aunque los ensambles mscorlib.dll y System.dll son mutuamente dependientes, le aconsejo que nunca tenga 2 ensamblados mutuamente dependientes.

En cuanto a los ciclos de dependencia entre hings como espacios de nombres, aconsejo usar NDepend para detectar y evitar dependency cycles.

alt text

extracto del artículo (que escribió): Control component dependencies to gain clean architecture

ciclos de dependencia entre los componentes conducen a lo que comúnmente se llama código espagueti o código enredado. Si el componente A depende de B que depende de C que depende de A, el componente A no puede desarrollarse y probarse independientemente de B y C. A, B y C forman una unidad indivisible, un tipo de supercomponente. Este supercomponente tiene un costo mayor que la suma del costo sobre A, B y C debido al fenómeno de la escala de diseño (bien documentado en Estimación del software: Desmitificación del arte negro por Steve McConnell). Básicamente, esto mantiene que el costo de desarrollar una pieza de código indivisible aumenta exponencialmente.

Esto sugiere que desarrollar y mantener 1,000 LOC (Líneas de código) probablemente costará tres o cuatro veces más que desarrollar y mantener 500 LOC, a menos que se pueda dividir en dos terrones independientes de 500 LOC cada uno. De ahí la comparación con spaghetti que describe un código enredado que no se puede mantener. Para racionalizar la arquitectura, uno debe asegurarse de que no haya ciclos de dependencia entre los componentes, sino también verificar que el tamaño de cada componente sea aceptable (500 a 1000 LOC).

+2

Una respuesta muy reflexiva e informativa. Solo quiero señalar, sin embargo, que principalmente estaba haciendo esta pregunta desde la perspectiva de querer escribir un componente en una combinación de C# y VB.NET. Así que aunque entiendo lo que quieres decir con "supercomponente", siento que no coincide exactamente con lo que buscaba. Para mí, un "supercomponente" sería la combinación de múltiples componentes mutuamente dependientes; un "componente mixto", como lo llamaré, por otro lado, sería la descomposición (por idioma) de un * componente * en partes * mutuamente dependientes *. ¿Tiene sentido? –

+0

Debe elegir VB.NET o C#, y migrar el otro idioma al idioma elegido (con la ayuda de .NET Reflector, por ejemplo, que puede convertir el código C# a VB.NET o viceversa). No puede haber buenas razones para mantener 2 idiomas para codificar el mismo ensamblaje. –

1

Si construye utilizando herramientas de línea de comandos, puede tener un ensamblaje que contenga muchos módulos. Cada módulo se puede compilar con un compilador diferente. Los módulos pueden tener dependencias circulares entre ellos.

Sin embargo, no espero que el estudio visiual lo haga.


También hay truco que puede hacer que le dirá al enlazador para redirigir una solicitud para un tipo de un montaje a otro. Microsoft los usa y luego mueven tipos dentro del marco .net. Esto solo tiene valor si no puedes obtener todas las llamadas para volver a compilar el código.

0

Es posible tener dependencias circulares en Visual Studio si usa la compilación condicional. La mayoría de las veces sería mejor eliminar la referencia circular para empezar, pero si tiene una buena razón para conservarla, se puede usar this solution como una solución para que se construya.

Cuestiones relacionadas