Eu tenho o seguinte código:
Func<string, bool> comparer = delegate(string value) {
return value != "0";
};
No entanto, o seguinte não é compilado:
var comparer = delegate(string value) {
return value != "0";
};
Por que o compilador não pode descobrir que é um Func<string, bool>
? Ele pega um parâmetro de string e retorna um booleano. Em vez disso, ele me dá o erro:
Não é possível atribuir método anônimo a uma variável local de tipo implícito.
Eu tenho um palpite e que, se a versão var compilada , falta consistência se eu tivesse o seguinte:
var comparer = delegate(string arg1, string arg2, string arg3, string arg4, string arg5) {
return false;
};
O exemplo acima não faria sentido, pois o Func <> permite apenas até 4 argumentos (no .NET 3.5, que é o que estou usando). Talvez alguém possa esclarecer o problema. Obrigado.
Func<>
aceita até 16 argumentos.Func<string, bool>
? Parece umConverter<string, bool>
para mim!Dim comparer = Function(value$) value <> "0"
Respostas:
Outros já apontaram que existem infinitos tipos possíveis de delegados que você poderia ter significado; o que é de cerca de tão especial
Func
que merece ser o padrão em vez dePredicate
ouAction
ou qualquer outra possibilidade? E, para lambdas, por que é óbvio que a intenção é escolher a forma delegada, em vez da forma da árvore de expressão?Mas poderíamos dizer que
Func
é especial e que o tipo inferido de um método lambda ou anônimo é Func de alguma coisa. Ainda teríamos todos os tipos de problemas. Que tipos você gostaria de deduzir para os seguintes casos?Não existe um
Func<T>
tipo que faça referência a nada.Não sabemos o tipo do parâmetro formal, apesar de conhecermos o retorno. (Ou nós? O retorno é int? Long? Short? Byte?)
Não sabemos o tipo de retorno, mas não pode ser anulado. O tipo de retorno pode ser qualquer tipo de referência ou qualquer tipo de valor anulável.
Novamente, não sabemos o tipo de retorno e, desta vez, pode ser anulado.
Isso pretende ser uma instrução lambda de retorno nulo ou algo que retorne o valor que foi atribuído a q? Ambos são legais; qual devemos escolher?
Agora, você pode dizer, bem, apenas não suporte nenhum desses recursos. Apenas suporte casos "normais" em que os tipos possam ser trabalhados. Isso não ajuda. Como isso facilita minha vida? Se o recurso funcionar algumas vezes e falhar algumas vezes, ainda tenho que escrever o código para detectar todas essas situações de falha e fornecer uma mensagem de erro significativa para cada uma. Ainda precisamos especificar todo esse comportamento, documentá-lo, escrever testes e assim por diante. Esse é um recurso muito caro que economiza ao usuário meia dúzia de pressionamentos de tecla. Temos maneiras melhores de agregar valor ao idioma do que gastar muito tempo escrevendo casos de teste para um recurso que não funciona na metade do tempo e que não oferece quase nenhum benefício nos casos em que funciona.
A situação em que é realmente útil é:
porque não existe um tipo "falável" para essa coisa. Mas temos esse problema o tempo todo e usamos apenas a inferência de tipo de método para deduzir o tipo:
e agora a inferência de tipo de método descobre qual é o tipo de função.
fonte
Apenas Eric Lippert sabe ao certo, mas acho que é porque a assinatura do tipo de delegado não determina exclusivamente o tipo.
Considere o seu exemplo:
Aqui estão duas inferências possíveis para o que
var
deveria ser:Qual o compilador deve inferir? Não há um bom motivo para escolher um ou outro. E embora a
Predicate<T>
seja funcionalmente equivalente aFunc<T, bool>
, eles ainda são tipos diferentes no nível do sistema de tipos .NET. O compilador, portanto, não pode resolver inequivocamente o tipo de delegado e deve falhar na inferência de tipo.fonte
Eric Lippert tem um post antigo sobre o assunto, onde ele diz
fonte
Delegados diferentes são considerados tipos diferentes. por exemplo,
Action
é diferente deMethodInvoker
e uma instância deAction
não pode ser atribuída a uma variável do tipoMethodInvoker
.Então, dado um delegado anônimo (ou lambda) como
() => {}
, é umAction
ou umMethodInvoker
? O compilador não pode dizer.Da mesma forma, se eu declarar um tipo de delegado pegando um
string
argumento e retornando umbool
, como o compilador saberia que você realmente queria um emFunc<string, bool>
vez do meu tipo de delegado? Não pode inferir o tipo de delegado.fonte
Os seguintes pontos são do MSDN em relação às variáveis locais de tipo implícito:
Referência do MSDN: variáveis locais implicitamente digitadas
Considerando o seguinte em relação aos métodos anônimos:
Referência do MSDN: Métodos Anônimos
Eu suspeitaria que, como o método anônimo pode realmente ter assinaturas de métodos diferentes, o compilador não pode inferir adequadamente qual seria o tipo mais apropriado a ser atribuído.
fonte
Minha postagem não responde à pergunta real, mas responde à pergunta subjacente de:
"Como evito ter que digitar algum tipo fugitivo como
Func<string, string, int, CustomInputType, bool, ReturnType>
?" [1]Sendo o programador preguiçoso / hacky que sou, experimentei usar
Func<dynamic, object>
- o que pega um único parâmetro de entrada e retorna um objeto.Para vários argumentos, você pode usá-lo da seguinte maneira:
Dica: você pode usar
Action<dynamic>
se não precisar retornar um objeto.Sim, eu sei que provavelmente vai contra seus princípios de programação, mas isso faz sentido para mim e provavelmente para alguns codificadores Python.
Sou muito novato nos delegados ... só queria compartilhar o que aprendi.
[1] Isso pressupõe que você não está chamando um método que requer
Func
um parâmetro predefinido. Nesse caso, você precisará digitar a sequência fugly: /fonte
Como é isso?
fonte