Tengo dos clases de contratos de negocios:delegados de acción, los genéricos, covarianza y contravarianza
public BusinessContract
public Person : BusinessContract
en otra clase Tengo el siguiente código:
private Action<BusinessContract> _foo;
public void Foo<T>(Action<T> bar) where T : BusinessContract
{
_foo = bar;
}
Lo anterior ni siquiera se compile, que me desconcierta un poco Estoy obligando a que T sea BusinessContract, ¿por qué el compilador no sabe que la barra se puede asignar a _foo?
Al tratar de evitar esto, hemos intentado cambiar a la siguiente:
public void Foo<T>(Action<T> bar) where T : BusinessContract
{
_foo = (Action<BusinessContract>)bar;
}
Ahora el compilador es feliz, así que escribir el siguiente código en otra parte de mi solicitud:
Foo<Person>(p => p.Name = "Joe");
Y la aplicación explota con una InvalidCastException en tiempo de ejecución.
No lo entiendo. ¿No debería ser capaz de convertir mi tipo más específico a un tipo menos específico y asignarlo?
ACTUALIZACIÓN
Jon responde a la pregunta, así nos dieron el visto bueno para eso, pero sólo para cerrar el bucle en esto, así es como terminamos la solución del problema.
private Action<BusinessContract> _foo;
public void Foo<T>(Action<T> bar) where T : BusinessContract
{
_foo = contract => bar((T)contract);
}
¿Por qué estamos haciendo esto? Tenemos un DAL falso que usamos para pruebas unitarias. Con uno de los métodos, debemos proporcionarle al desarrollador de la prueba la capacidad de especificar qué debe hacer el método cuando se lo llama durante la prueba (es un método de actualización que actualiza un objeto almacenado en la memoria caché de la base de datos). El propósito de Foo es establecer lo que debería suceder cuando se llama a la actualización. IOW, en otra parte de esta clase tenemos lo siguiente.
public void Refresh(BusinessContract contract)
{
if(_foo != null)
{
_foo(contract);
}
}
El desarrollador de la prueba podría entonces, por ejemplo, decidir que quería establecer el nombre a un valor diferente cuando se llamó a Refresh.
Foo<Person>(p => p.Name = "New Name");
@MDeSchaepmeester: No, no lo estoy - en el código de trabajo (la segunda mitad de la publicación) estoy asignando un valor 'Action
Tienes razón, error tonto, en realidad no leí ese código y asumí que llamabas a Foo con _foo como parámetro (Vine aquí porque estaba haciendo * eso *) – MarioDS