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:
ContractClassFor
atributo.
No funciona, porque la clase de destino debe apuntar a la clase de contrato.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 atributoContractDeclarativeAssembly
, 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.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
¿Puede usted reflejar el otro conjunto y simplemente descompilarlo? –
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. –
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. –