Pergunta

Sou novo em todos os recursos anônimos e preciso de ajuda.Eu fiz o seguinte funcionar:

public void FakeSaveWithMessage(Transaction t)
{
    t.Message = "I drink goats blood";
}

public delegate void FakeSave(Transaction t);

public void SampleTestFunction()
{
    Expect.Call(delegate { _dao.Save(t); }).Do(new FakeSave(FakeSaveWithMessage));
}

Mas isso é totalmente feio e eu gostaria que o interior do Do fosse um método anônimo ou até mesmo um lambda se for possível.Tentei:

Expect.Call(delegate { _dao.Save(t); }).Do(delegate(Transaction t2) { t2.Message = "I drink goats blood"; });

e

Expect.Call(delegate { _dao.Save(t); }).Do(delegate { t.Message = "I drink goats blood"; });

mas estes me dão

Não é possível converter o método anônimo para o tipo 'System.Delegate' porque não é um tipo delegado ** erros de compilação.

O que estou fazendo de errado?


Por causa do que Mark Ingram postou, parece que a melhor resposta, embora ninguém tenha dito isso explicitamente, é fazer o seguinte:

public delegate void FakeSave(Transaction t);

Expect.Call(delegate { _dao.Save(t); }).Do( new FakeSave(delegate(Transaction t2) { t.Message = expected_msg; }));
Foi útil?

Solução

Essa é uma mensagem de erro bem conhecida.Verifique o link abaixo para uma discussão mais detalhada.

http://staceyw1.wordpress.com/2007/12/22/they-are-anonymous-methods-not-anonymous-delegates/

Basicamente você só precisa colocar um elenco na frente do seu delegado anônimo (sua expressão lambda).

Caso o link caia, aqui está uma cópia da postagem:

São Métodos Anônimos, não Delegados anônimos.
Postado em 22 de dezembro de 2007 por staceyw1

Não é apenas um ponto de discussão porque queremos ser difíceis.Isso nos ajuda razão sobre o que exatamente está acontecendo.Para ser claro, não existe isso como delegado anônimo.Não existem (ainda não).Eles são "Anônimos" Métodos" – ponto.Importa em como pensamos neles e na forma como falamos eles.Vamos dar uma olhada no Instrução de método anônimo "delegate() {...}".Na verdade, são dois diferentes operações e quando pensamos nisso Dessa forma, nunca seremos confundidos outra vez.A primeira coisa que o compilador faz é criar o método anônimo sob as capas usando o inferido Delegar assinatura como método assinatura.Não é correto dizer o método é "unnamed" porque tem um nome e o compilador atribui-o.Está apenas escondido de visão normal.A próxima coisa que ele faz é criar um objeto delegado do Tipo necessário para encapsular o método.Este é chamado de inferência delegada e pode seja a fonte dessa confusão.Durante isso para funcionar, o compilador deve ser capaz de descobrir (i.e.inferir) o que Delegar tipo que ele criará.Tem ser um tipo de concreto conhecido.Deixar Escreva algum código para ver o porquê.

private void MyMethod()
{
}

Não compila:

1) Delegate d = delegate() { };                       // Cannot convert anonymous method to type ‘System.Delegate’ because it is not a delegate type
2) Delegate d2 = MyMethod;                         // Cannot convert method group ‘MyMethod’ to non-delegate type ‘System.Delegate’
3) Delegate d3 = (WaitCallback)MyMethod;   // No overload for ‘MyMethod’ matches delegate ‘System.Threading.WaitCallback’

A linha 1 não é compilada porque o compilador não pode inferir qualquer delegado tipo.Ele pode ver claramente a assinatura Desejamos, mas não há concreto Delegar tipo que o compilador pode ver.Ele poderia criar um tipo anônimo de tipo delegado para nós, mas não Trabalhe assim.Linha 2 não compilar por um motivo semelhante.Mesmo embora o compilador conheça o método assinatura, não estamos dando um delegar tipo e não é só ir para escolher um que por acaso funcione (não que efeitos colaterais que poderiam tem).A linha 3 não funciona porque propositalmente descombinamos o método assinatura com um delegado com um assinatura diferente (como WaitCallback toma e objeta).

Compila:

4) Delegate d4 = (MethodInvoker)MyMethod;  // Works because we cast to a delegate type of the same signature.
5) Delegate d5 = (Action)delegate { };              // Works for same reason as d4.
6) Action d6 = MyMethod;                                // Delegate inference at work here. New Action delegate is created and assigned.

Em contraste, estes funcionam.Obras da Linha 1 porque dizemos ao compilador o que delegar o tipo a ser usado e eles correspondem, Então funciona.A Linha 5 trabalha para o mesmo motivo.Nota que usamos o especial forma de "delegar" sem os parens.O compilador infere o método assinatura do elenco e cria o método anônimo com o mesmo assinatura como delegado inferido tipo.A Linha 6 funciona porque o MyMethod() e Action usam o mesmo assinatura.

Eu espero que isso ajude.

Veja também: http://msdn.microsoft.com/msdnmag/issues/04/05/C20/

Outras dicas

O que Marcos disse.

O problema é que Do usa um parâmetro Delegate.O compilador não pode converter os métodos anônimos em Delegado, apenas um "tipo delegado", ou seja,um tipo concreto derivado de Delegate.

Se aquela função Do tivesse executado Action<>, Action<,> ...etc.sobrecargas, você não precisaria do elenco.

O problema não está na sua definição de delegado, é que o parâmetro do método Do() é do tipo System.Delegate, e o tipo de delegado gerado pelo compilador (FakeSave) não é convertido implicitamente em System.Delegate.

Tente adicionar um elenco na frente do seu delegado anônimo:

Expect.Call(delegate { _dao.Save(t); }).Do((Delegate)delegate { t.Message = "I drink goats blood"; });

Tente algo como:

Expect.Call(delegate { _dao.Save(t); }).Do(new EventHandler(delegate(Transaction t2) { t2.CheckInInfo.CheckInMessage = "I drink goats blood"; }));

Observe o EventHandler adicionado ao redor do delegado.

EDITAR:pode não funcionar, pois as assinaturas de função do EventHandler e do delegado não são as mesmas...A solução que você adicionou ao final da sua pergunta pode ser o único caminho.

Como alternativa, você pode criar um tipo de delegado genérico:

public delegate void UnitTestingDelegate<T>(T thing);

Para que o delegado não seja específico da transação.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top