2010-10-22 8 views
5

El objetivo final es especificar contratos para una clase que reside en un ensamblaje externo que no tengo control (es decir, no puedo simplemente agregar contratos a esa clase directamente).Crear contratos de código para una biblioteca heredada

Lo que he intentado hasta ahora:

  1. ContractClassFor atributo.
    No funciona, porque la clase de destino debe apuntar a la clase de contrato.

  2. Construya manualmente un conjunto de referencia de contrato (es decir, MyAsm.Contracts.dll) mediante la ingeniería inversa de los autogenerados.
    No funciona, porque justo después de compilarlo, el reescritor aparece y elimina convenientemente el atributo ContractDeclarativeAssembly, lo que hace que el ensamblaje sea irreconocible por las herramientas como "ensamblaje de referencia de contrato". Y no puedo encontrar una manera de apagar la reescritura.

  3. Cree un ensamblaje "falso" con el mismo nombre, versión, nombre seguro (si lo hay) y otros atributos como el ensamblado de destino, y coloque las mismas clases con los mismos métodos allí nombrados. Luego, compile ese ensamblaje con la opción "construir referencia de contrato" activada, luego tome el ensamblaje de referencia de contrato generado y úselo.
    Esto tampoco funcionó por alguna razón, aunque no tengo idea de cuál fue exactamente esa razón. El verificador estático simplemente ignora el conjunto de referencia generado por mis smartypants, como si no existiera.

Y una cosa más, por si acaso es importante: el conjunto de señal se compila para .NET 2.0, y no puede volver a compilar el 4,0.

actualización

Escribir una biblioteca "contenedor" con contratos definidos está fuera de cuestión.

Por un lado, es un código extra para escribir. Pero incluso si lo deja de lado, puede ser una penalización de rendimiento significativa: tendría que (potencialmente) crear clases contenedoras para cada tipo de "herencia" que se utiliza como tipo de devolución de mis métodos "heredados". Pero incluso ese no es el final de la historia. Imagínese que algunos métodos pueden devolver referencias a interfaces base, y luego el código de llamadas puede convertirlas en interfaces derivadas para ver si el objeto admite más funcionalidades. ¿Cómo los envuelvo? Probablemente tendré que proporcionar métodos personalizados Cast<T>() en mis clases de ajuste, que intentarán lanzar la clase/interfaz subyacente y devolver un contenedor para el resultado si es exitoso. Al final, toda mi base de código se volverá tan intrincada que probablemente no valga la pena de todos modos.

Por otro lado, precisamente este problema ya ha sido resuelto con éxito por el propio equipo de CC: ellos envían ensambles de referencia de contrato adecuados para mscorlib, System.Core y algunos otros ensambles de sistemas, ¿no? ¿Cómo se las arreglaron para construirlos? Si pueden hacerlo, entonces no veo ninguna razón por la cual no pueda realizar el mismo truco.

Bueno, en realidad, veo una razón: no sé cómo hacerlo. :-) - Fyodor Soikin hace 18 segundos editar

+0

¿Puede usted reflejar el otro conjunto y simplemente descompilarlo? –

+0

No necesito descompilar, de hecho tengo el código fuente para eso. Pero el objetivo no es modificar ese código. También se usa en otros proyectos, que apuntan a 2.0, por lo tanto, incluso el cambio más pequeño posible de agregar atributos '[ContractClass]' rompería esos proyectos. Y tampoco quiero ramificar el código fuente, porque entonces obtendría el real dolor de fusionar futuros cambios en esa rama. –

+0

Bueno, si mantiene la fuente usted mismo, sería muy fácil para usted mantener una rama 2.0 y una 4.0 de los contratos si usa git/mercurial donde la rama 2.0 es la predeterminada y la 4.0 es una rama característica, cuando se agregan propiedades/cambiado a la rama predeterminada después de eso todo lo que necesita hacer es usar el DVCS para fusionar los cambios en la rama 4.0 entonces. Esto sería muy poco trabajo siempre que se asegure de que el único código que cambie en la rama 4.0 esté relacionado con el código de contratos C# y no con las clases mismas. –

Respuesta

4

Probablemente estuvo casi allí con (2). Asegúrese de desactivar la reescritura de contrato para el ensamblaje C# que construya a mano. Desactive todas las comprobaciones en tiempo de ejecución y el análisis estático, y no vuelva a activarse el regrabador. Colóquelo en todos los demás ensamblajes de CodeContracts, p. Ej. para /bin/X.dll, cree un ensamblado que vaya a /bin/CodeContracts/X.Contracts.dll.

Ver http://social.msdn.microsoft.com/Forums/en-US/codecontracts/thread/5fe7ad4e-d4f1-4bb5-806e-a1e31f550181. Tenías razón, solo crea todos los bits correctos mirando Reflector y funciona. Quería hacer esto para agregar contratos a mi ensamblaje de F # hasta que F # pueda manejar los contratos.

+0

No estoy seguro de cómo sucedió, pero de alguna manera me he perdido la casilla que desactiva la reescritura . Y ahora que miré por segunda vez y lo encontré, todo funciona bien. ¡Muchas gracias! –

1

Una solución alternativa podría ser crear una capa de "fachada" entre el código y el ensamblaje externo. Esta capa puede contener todos los contratos que aplicarías en el código externo.

Si no desea cambiar nada en el código existente, me temo que no hay mucho más que pueda hacer.

+0

Bueno, sí, eso es básicamente lo que estoy haciendo en este momento. Por un lado, es mucho código adicional para escribir. Pero incluso si lo deja de lado, puede ser una penalización de rendimiento significativa: tendría que (potencialmente) crear clases contenedoras para cada tipo de "herencia" que se utiliza como tipo de devolución de mis métodos "heredados". Pero incluso ese no es el final de la historia. Imagínese que algunos métodos pueden devolver referencias a interfaces base, y luego el código de llamadas puede convertirlas en interfaces derivadas para ver si el objeto admite más funcionalidades. ¿Cómo los envuelvo? Envolver toda una biblioteca es un gran esfuerzo. –

+0

Por otro lado, precisamente este problema ya ha sido resuelto con éxito por el propio equipo de CC: ellos envían ensambles de referencia de contrato adecuados para mscorlib, System.Core y algunos otros ensambles de sistema, ¿no? ¿Cómo se las arreglaron para construirlos? Si pueden hacerlo, entonces no veo ninguna razón por la cual no pueda realizar el mismo truco. Oh, bueno, en realidad, veo una razón: no sé cómo hacerlo. :-) –

+2

Al ver que la clase Contract es parte del BCL, supongo que tienen acceso al código mscorlib =) – koenmetsu

Cuestiones relacionadas