elegados de ação, genéricos, covariância e contravariânc
Tenho duas classes de contrato de negócios:
public BusinessContract
public Person : BusinessContract
Em outra classe, tenho o seguinte código:
private Action<BusinessContract> _foo;
public void Foo<T>( Action<T> bar ) where T : BusinessContract
{
_foo = bar;
}
O acima não compila, o que me deixa um pouco desconcertado. Estou restringindo T a ser BusinessContract, então por que o compilador não sabe que a barra pode ser atribuída a _foo?
Ao tentar contornar isso, tentamos alterá-lo para o seguinte:
public void Foo<T>( Action<T> bar ) where T : BusinessContract
{
_foo = (Action<BusinessContract>)bar;
}
Agora, o compilador está satisfeito, então escrevo o seguinte código em outro lugar do meu aplicativo:
Foo<Person>( p => p.Name = "Joe" );
E o aplicativo explode com uma InvalidCastException em tempo de execuçã
Eu não entendo. Não posso converter meu tipo mais específico para um tipo menos específico e atribuí-lo?
ATUALIZA
Jon respondeu à pergunta, então conseguiu o que queria, mas, para fechar o ciclo, veja como acabamos resolvendo o problem
private Action<BusinessContract> _foo;
public void Foo<T>( Action<T> bar ) where T : BusinessContract
{
_foo = contract => bar( (T)contract );
}
Por que estamos fazendo isso? Temos um DAL falso que usamos para testes de unidade. Com um dos métodos, precisamos fornecer ao desenvolvedor do teste a capacidade de especificar o que o método deve fazer quando for chamado durante o teste (é um método de atualização que atualiza um objeto em cache do banco de dados). O objetivo do Foo é definir o que deve acontecer quando a atualização é chamada. Em outras partes desta classe, temos o seguinte.
public void Refresh( BusinessContract contract )
{
if( _foo != null )
{
_foo( contract );
}
}
O desenvolvedor de teste pode então, por exemplo, decidir que deseja definir o nome para um valor diferente quando a atualização for chamad
Foo<Person>( p => p.Name = "New Name" );