2009-08-22 14 views
97

En el BCL .NET hay referencias circulares entre:¿Cómo creó Microsoft ensamblajes que tienen referencias circulares?

  • System.dll y System.Xml.dll
  • System.dll y System.Configuration.dll
  • System.Xml.dll y System.Configuration.dll

Aquí hay una captura de pantalla de .NET Reflector que muestra lo Quiero decir:

enter image description here

Cómo es que Microsoft creó estos conjuntos es un misterio para mí. ¿Se requiere un proceso de compilación especial para permitir esto? Imagino que algo interesante está sucediendo aquí.

+2

Muy buena pregunta. Nunca me he tomado el tiempo para inspeccionar esto, pero tengo curiosidad por saber la respuesta. De hecho, parece que Dykam ha proporcionado una sensata. – Noldorin

+3

¿por qué esos dll no se fusionan en uno, si todos se requieren el uno al otro? ¿Hay alguna razón práctica para eso? –

+1

Pregunta interesante ... ¡Me gustaría saber la respuesta de Eric Lippert a esta pregunta! Y como dijo Andreas, me pregunto por qué no pusieron todo en la misma asamblea ... –

Respuesta

53

Solo puedo decir cómo lo hace Mono Project. El teorema es bastante simple, aunque da un desorden de código.

Primero compilan System.Configuration.dll, sin la parte que necesita la referencia a System.Xml.dll. Después de esto, compilan System.Xml.dll de la manera normal. Ahora viene la magia. Recompilan System.configuration.dll, con la parte que necesita la referencia a System.Xml.dll. Ahora hay una compilación exitosa con la referencia circular.

En resumen:

  • A se compila sin el código pueda B y la referencia a B.
  • B se compila.
  • A se recompila.
+0

Está bloqueado por Visual Studio, pero se puede hacer mediante el compilador de línea de comandos (csc.exe) directamente. Ver mi respuesta –

+14

Lo sé. El sistema de compilación principal de Mono no es Visual Studio. Guess Microsofts tampoco lo es. – Dykam

6

Supongo que se podría hacer comenzando con un conjunto acíclico de ensamblajes y usando ILMerge para unir los ensamblajes más pequeños en grupos lógicamente relacionados.

1

Un posible enfoque es utilizar la compilación condicional (#if) para compilar primero un System.dll que no dependa de esos otros ensamblados, luego compilar los otros ensamblajes y finalmente recompilar System.dll para incluir las partes dependiendo de Xml y Configuración.

+1

Lamentablemente esto no le permite referenciar condicionalmente un ensamblaje (desearía que fuera posible, realmente ayudaría en uno de mis proyectos ...) –

+1

Las referencias condicionales se pueden hacer fácilmente editando el archivo .csproj. Simplemente agregue un atributo de Condición al elemento . – Daniel

4

Bueno, nunca lo he hecho en Windows, pero lo he hecho en muchos de los entornos compile-link-rtl que sirvieron como los progenitores prácticos para ello. Lo que debe hacer primero es crear "objetivos" sin las referencias cruzadas, luego vincular, luego agregar las referencias circulares, luego volver a vincular. En general, los vinculadores no se preocupan por los ref circulares ni por las cadenas de ref, solo se preocupan por poder resolver cada referencia por sí mismos.

Así que si usted tiene dos bibliotecas, A y B que tienen que hacer referencia a unos de otros, intentar algo como esto:

  1. Enlace A, sin ninguna referencias a B.
  2. Enlace B con referencias a A.
  3. Enlace A, agregando los refs a B.

dykam hace un buen punto, es compilar, no vincular en .Net, pero el principio sigue siendo el mismo: Haga sus fuentes de referencias cruzadas, con sus puntos de entrada exportados, pero con todos menos uno de ellos teniendo sus propias referencias a los otros aplastados. Constrúyalos así. Luego, quita las referencias externas y reconstruyelas. Esto debería funcionar incluso sin herramientas especiales, de hecho, este enfoque ha funcionado en todos los sistemas operativos en los que lo haya probado alguna vez (alrededor de 6 de ellos). Aunque obviamente algo que lo automatiza sería una gran ayuda.

+0

el teorema es correcto. Sin embargo, en el mundo de .Net, la vinculación se realiza de forma dinámica y no es un problema. Es el paso de compilación donde se necesita esta solución. – Dykam

+0

Lamento repararlo de nuevo: P. Pero la referencia (vinculación) en tiempo de compilación ocurre en el mundo .Net, que es todo lo que se deriva de esa especificación ECMA específica. Por lo tanto, Mono, dotGnu y .Net. No es Windows mismo. – Dykam

+0

Heh, es suficiente. – RBarryYoung

25

Se puede hacer de la forma descrita por Dykam pero Visual Studio te impide hacerlo.

Deberá usar directamente el compilador de línea de comandos csc.exe.

  1. csc/target: ClassA.cs biblioteca

  2. csc/target: ClassB.cs biblioteca /reference:ClassA.dll

  3. csc/target: ClassA.cs biblioteca ClassC. cs /reference:ClassB.dll


//ClassA.cs 
namespace CircularA { 
    public class ClassA { 
    } 
} 


//ClassB.cs 
using CircularA; 
namespace CircularB { 
    public class ClassB : ClassA { 
    } 
} 


//ClassC.cs 
namespace CircularA { 
    class ClassC : ClassB { 
    } 
} 
+0

También puede hacerlo en Visual Studio aunque es bastante duro, la forma básica es usar # if's y eliminar la referencia utilizando el explorador de soluciones, revirtiendo eso en el tercer paso. Otra forma en la que estoy pensando es en un tercer archivo de proyecto que incluye los mismos archivos pero diferentes referencias. Esto funcionaría, ya que puede especificar el orden de compilación. – Dykam

+0

Por lo que sé, no puedo probarlo aquí. – Dykam

+0

Realmente me gustaría ver eso. De lo que experimenté aquí, en el momento que intentas agregar referencia, el IDE te detiene. –

35

RBarryYoung y dykam son en somethi ng. Microsoft usa una herramienta interna que usa ILDASM para desmontar ensamblajes, eliminar todos los elementos internos y privados y los cuerpos de métodos, y recompilar IL nuevamente (usando ILASM) en lo que se denomina 'ensamblaje deshidratado' o ensamblaje de metadatos. Esto se hace cada vez que se cambia la interfaz pública de ensamblaje.

Durante la compilación, se utilizan conjuntos de metadatos en lugar de los reales. De esa manera el ciclo se rompe.

+1

Interesante respuesta, ¿tiene algún vínculo? –

+0

Estoy tratando de encontrar una referencia externa a la herramienta. No creo que se publique fuera de Microsoft, pero el concepto es simple: desmontar las partes internas: volver a montar. –

+0

De acuerdo, respuesta interesante. Algunos enlaces para respaldar esto serían buenos. –

16

Es bastante fácil de hacer en Visual Studio, siempre y cuando no se utiliza referencias de proyectos ... Prueba esto:

  1. Visual Studio abierto
  2. Crear 2 proyectos Biblioteca de clases "ClassLibrary1" & " ClassLibrary2 ".
  3. Build
  4. De ClassLibrary1 añadir una referencia a ClassLibrary2 navegando a la DLL creado en el paso 3.
  5. De ClassLibrary2 añadir una referencia a ClassLibrary1 navegando a la DLL creado en el paso 3.
  6. construir de nuevo (Nota: si realiza cambios en ambos proyectos, deberá construir dos veces para que ambas referencias sean "nuevas")

Así es como lo hace. Pero en serio ... ¡Nunca lo hagas en un proyecto real! Si lo haces, Santa no te traerá ningún regalo este año.

0

Técnicamente, es posible que no se hayan compilado en absoluto y se hayan ensamblado a mano. Estas son bibliotecas de bajo nivel, después de todo.

+0

No realmente.No hay muchas cosas de bajo nivel, solo básicas. ¿Qué te hizo pensar que sería de bajo nivel? El tiempo de ejecución y corlib son de bajo nivel. Relativamente. Todavía claro C o C++, pensó que el JIT contiene cosas de bajo nivel. – Dykam

Cuestiones relacionadas