Pregunta

Puede alguien explicar el siguiente comportamiento?

En resumen, si crea múltiples compatible con CLS bibliotecas de Visual Studio 2008 y haga que comparten una raíz de espacio de nombres comunes, una biblioteca de referencia a otra biblioteca requerir las referencias a ese de la biblioteca referencias a pesar de que no consumirlos.

Es bastante difícil de explicar en una sola frase, pero aquí están los pasos para reproducir el comportamiento (prestar mucha atención a los espacios de nombres):

Crea una biblioteca llamada LibraryA y añadir una clase única de esa biblioteca:

namespace Ploeh
{
    public abstract class Class1InLibraryA
    {
    }
}

Asegúrese de que la biblioteca es compatible con CLS añadiendo [assembly: CLSCompliant(true)] a AssemblyInfo.cs.

Cree otra biblioteca llamada LibraryB y referencia LibraryA. Añadir a las siguientes clases LibraryB:

namespace Ploeh.Samples
{
    public class Class1InLibraryB : Class1InLibraryA
    {
    }
}

y

namespace Ploeh.Samples
{
    public abstract class Class2InLibraryB
    {
    }
}

Asegúrese de que LibraryB también es compatible con CLS.

Tenga en cuenta que Class1InLibraryB deriva de un tipo de LibraryA, mientras que Class2InLibraryB no lo hace.

Ahora cree una tercera biblioteca llamada LibraryC y referencia LibraryB (pero no LibraryA). Añadir la siguiente clase:

namespace Ploeh.Samples.LibraryC
{
    public class Class1InLibraryC : Class2InLibraryB
    {
    }
}

Esto todavía debe compilar. Observe que Class1InLibraryC deriva de la clase en LibraryB que no utiliza ningún tipo de LibraryA .

Observe también que Class1InLibraryC se define en un espacio de nombres que es parte de la jerarquía del espacio de nombres definido en LibraryB.

Hasta ahora, LibraryC no tiene ninguna referencia a LibraryA, y ya que no utiliza tipos de LibraryA, la solución compila.

Ahora haga compatible LibraryC CLS también. De repente, la solución ya no se compila, que le da este mensaje de error:

  

El tipo 'Ploeh.Class1InLibraryA' se define en un montaje que no se hace referencia. Debe agregar una referencia al ensamblado 'Ploeh, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null'.

Puede hacer que la solución compilar de nuevo en una de las siguientes maneras:

  • Eliminar CLS Cumplimiento de LibraryC
  • Añadir una referencia a LibraryA (aunque no lo necesita)
  • Cambiar el espacio de nombres en LibraryC de modo que no es parte de la jerarquía del espacio de nombres de LibraryB (por ejemplo a Fnaah.Samples.LibraryC)
  • Cambiar el espacio de nombres de Class1InLibraryB (es decir, el no utiliza desde LibracyC) para que se no se encuentra en la jerarquía del espacio de nombres de LibraryC (por ejemplo a Ploeh.Samples.LibraryB)

Parece que hay alguna extraña interacción entre la jerarquía de espacio de nombres y compatibilidad con CLS.

La solución de este problema se puede hacer escogiendo una de las opciones de la lista anterior, pero puede alguien explicar el razón detrás de este comportamiento?

¿Fue útil?

Solución

Yo tenía un aspecto en los documentos oficiales para el CLS ( http: // msdn.microsoft.com/en-us/netframework/aa569283.aspx ), pero mi cabeza explotó antes de que pudiera encontrar una respuesta simple.

Pero creo que la base es que el compilador, con el fin de verificar el cumplimiento de CLS LibraryC, tiene que buscar los posibles conflictos de nombre con LibraryA.

el compilador debe verificar todas las "partes de un tipo que están fuera accesible o visible del conjunto de la definición de" (CLS Regla 1).

Desde public class Class1InLibraryC hereda Class2InLibraryB, se debe verificar la compatibilidad con CLS contra LibraryA así, en particular, debido a que "Ploeh. *" Es ahora "en su alcance" para la Regla CLS 5 "Todos los nombres introducidos en un ámbito compatible con CLS deberá ser distinto independiente de la especie".

El cambio ya sea el espacio de nombres de Class1InLibraryB o Class1InLibraryC para que se conviertan distinta parece convencer al compilador que no hay posibilidad de un conflicto de nombres más.

Si elige la opción (2), añadir la referencia y compilar, verá que la referencia no es en realidad marcada en el meta-datos de conjunto resultante, así que esto es sólo una dependencia de compilación / verificación en tiempo.

Otros consejos

Recuerde que el CLS es un conjunto de reglas que se aplican a los conjuntos generados y está diseñado para soportar la interoperabilidad entre las lenguas. En cierto sentido, se define el subconjunto común más pequeño de reglas que un tipo debe seguir para asegurarse de que es el lenguaje y la plataforma agnóstica. CLS-cumplimiento sólo se aplica a los elementos que son visibles fuera de su asamblea de definir.

En cuanto a algunos de los códigos directrices compatible con CLS debe seguir:

  • Evite el uso de nombres de uso común como palabras clave en los lenguajes de programación.
  • No hay que esperar a los usuarios del marco que ser capaz de autor tipos anidados.
  • Se supone que las implementaciones de los métodos del mismo nombre y la firma en diferentes interfaces son independientes.

Las reglas para determinar CLS-cumplimiento son:

  • Cuando una asamblea no lleva un System.CLSCompliantAttribute explícita, será asumido para llevar a System.CLSCompliantAttribute (false).
  • Por defecto, un tipo hereda el atributo CLS-cumplimiento de su tipo envolvente (para tipos anidados) o adquiere el nivel de cumplimiento unido a su montaje (para tipos de nivel superior).
  • Por defecto, otros miembros (métodos, campos, propiedades y eventos) hereda el CLS-cumplimiento de su tipo.

Ahora, en lo que se refiere al compilador, (CLS Regla 1) debe ser capaz de aplicar las reglas de CLS-cumplimiento a cualquier información que será exportado fuera del montaje y la considera un tipo de ser compatible con CLS si todas sus partes accesibles al público (aquellas clases, interfaces, métodos, campos, propiedades y eventos que están disponibles para la ejecución de código en otro conjunto) o bien

  • tienen firmas compuestas sólo de tipos compatibles con CLS, o
  • están específicamente señaladas como no compatible con CLS.

Por reglas CTS, un alcance es simplemente un grupo / colección de nombres y dentro de un alcance un nombre puede referirse a múltiples entidades, siempre y cuando son de diferentes tipos (métodos, campos, tipos anidados, propiedades, eventos) o tienen diferentes firmas. Una entidad llamada tiene su nombre en exactamente un alcance lo que a fin de identificar tanto que la entrada de un alcance y un nombre se debe aplicar. El alcance califica el nombre.

Dado que los tipos se denominan, los nombres de los tipos se agrupan también a ámbitos. Para identificar un tipo totalmente, el nombre del tipo debe ser calificada por el alcance. Tipos de nombres están en el ámbito de la asamblea que contiene la aplicación de ese tipo.

Por ámbitos que son compatible con CLS, todos los nombres deben ser distintas independiente del tipo, excepto donde los nombres son idénticos y se resolvieron a través de la sobrecarga. En otras palabras, mientras que el CTS permite que un solo tipo de utilizar el mismo nombre para un campo y un método, el CLS no lo hace (CLS Regla 5).

tipos

Teniendo esto un paso más allá, un tipo compatible con CLS no debe requerir la aplicación de los no compatible con CLS (CLS Regla 20) y también debe heredar de otro tipo CLS-queja (CLS Regla 23).

Un conjunto puede depender de otros conjuntos de si las implementaciones en el alcance de los recursos de referencia uno de montaje cuyo ámbito en o propiedad de otro conjunto.

  • Todas las referencias a otros conjuntos se resuelven bajo el control del alcance de montaje actual.
  • Siempre es posible determinar qué conjunto de alcance una implementación particular se está ejecutando en. Todas las solicitudes procedentes de que alcance el montaje se resuelven en relación con ese ámbito.

Lo que todo esto significa es que en última instancia, con el fin de verificar el cumplimiento con CLS de un tipo, el compilador debe ser capaz de verificar que todos partes públicas de ese tipo son también compatibles con CLS. Esto significa que se debe garantizar que el nombre es único dentro de un ámbito, que no depende de los no compatibles con CLS tipos de partes de su propia aplicación y que hereda de otros tipos que son también compatible con CLS. La única manera para que lo haga es mediante el examen de todo el culoemblies que las referencias de tipo.

Recuerde que el paso de generación en Visual Studio es esencialmente una envoltura GUI torno a la ejecución de MSBuild, que en definitiva no es más que una forma de guión para llamar a la línea de comandos de C # compilador. Para que el compilador para verificar CLS-cumplimiento de un tipo, se debe saber y ser capaz de encontrar todos los conjuntos ese tipo referencias (no el proyecto). Ya que se llama a través de MSBuild y en última instancia de Visual Studio, la única manera para Visual Studio (MSBuild) que le informe de las asambleas es mediante su inclusión como referencias.

Obviamente, ya que el compilador es capaz de averiguar que está "perdido" referencias con el fin de verificar el cumplimiento y CLS-compilar correctamente, habría sido agradable si podría haber simplemente incluidos los de referencia de forma automática en nuestro nombre. El problema aquí es en la determinación de que versión del ensamblado para incluir y donde que el montaje está en el sistema de archivos. Al obligar a los desarrolladores para proporcionar esa información, el compilador ayuda a garantizar que se da la información correcta. Esto también tiene el efecto secundario de asegurar que todos los ensamblados dependientes se copian en las carpetas o Debug/bin Release/bin durante la compilación por lo que están en el directorio correcto cuando se ejecuta la aplicación después de que se ha compilado.

El problema se soluciona en Roslyn, que está disponible en Visual Studio 14.
A partir de julio de 2014, la CTP actual es aquí .
Ver este informe de error para obtener más información.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top