c# 4.0 - ¿Por qué no puedo agregar Contract.Requires en un método reemplazado?
c#-4.0 code-contracts (2)
Estoy usando código de contrato (en realidad, aprendiendo a usar esto).
Me estoy enfrentando a algo extraño ... Anulo un método, definido en una asamblea de terceros. Quiero agregar una declaración Contract.Require
como esta:
public class MyClass: MyParentClass
{
protected override void DoIt(MyParameter param)
{
Contract.Requires<ArgumentNullException>(param != null);
this.ExecuteMyTask(param.Something);
}
protected void ExecuteMyTask(MyParameter param)
{
Contract.Requires<ArgumentNullException>(param != null);
/* body of the method */
}
}
Sin embargo, recibo advertencias como esta:
Warning 1 CodeContracts: El método ''MyClass.DoIt (MyParameter)'' anula ''MyParentClass.DoIt (MyParameter))'', por lo tanto no puede agregar Requires.
[edit] cambió un poco el código para mostrar problemas alternativos [/ edit]
Si elimino el Contract.Requires
en el método DoIt, recibo otra advertencia, diciéndome que debo proporcionar un param != null
no comprobado param != null
No entiendo esta advertencia. ¿Cuál es la causa y puedo resolverlo?
No puede agregar requisitos adicionales que las personas que llaman pueden desconocer. Viola el Principio de Substitución de Liskov . El punto del polimorfismo es que un llamador debería ser capaz de tratar una referencia que en realidad se refiere a una instancia de su clase derivada como si se refiriera a una instancia de la clase base.
Considerar:
MyParentClass foo = GetParentClassFromSomewhere();
DoIt(null);
Si se determina estáticamente que es válido, es incorrecto que su clase derivada levante la mano y diga "¡No! ¡No se supone que llame a DoIt
con un argumento nulo!" El objetivo del análisis estático de los contratos es que puede determinar la validez de las llamadas, la lógica, etc. en tiempo de compilación ... por lo que no se pueden agregar restricciones adicionales en el tiempo de ejecución, que es lo que sucede aquí debido al polimorfismo.
Una clase derivada puede agregar garantías sobre lo que hará, lo que garantizará, pero no puede exigir más a sus interlocutores que utilicen métodos anulados.
Me gustaría señalar que puede hacer lo que Jon sugirió (esta respuesta se agrega a la suya ) pero también tiene su contrato sin violar el LSP .
Puede hacerlo reemplazando la palabra clave override
por new
.
La base sigue siendo la base; todo lo que hizo fue introducir otra funcionalidad (como las palabras clave sugieren literalmente).
No es ideal para la comprobación estática porque la seguridad se puede descartar fácilmente (primero se transfiere a la clase base y luego se llama al método), pero eso es obligatorio, porque de lo contrario violaría el LSP y no querría hacerlo obviamente. Mejor que nada, diría yo.
En un mundo ideal también podría anular el método y llamar al nuevo, pero C # no le permitiría hacerlo porque los métodos tendrían las mismas firmas (incluso si tuviera perfecto sentido, esa es la compensación).