Esta é apenas uma pergunta de curiosidade que eu queria saber se alguém tinha uma boa resposta para:
Na Biblioteca de classes do .NET Framework, temos, por exemplo, esses dois métodos:
public static IQueryable<TSource> Where<TSource>(
this IQueryable<TSource> source,
Expression<Func<TSource, bool>> predicate
)
public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate
)
Por que eles usam em Func<TSource, bool>
vez de Predicate<TSource>
? Parece que o Predicate<TSource>
é utilizado apenas por List<T>
e Array<T>
, enquanto Func<TSource, bool>
é utilizado por praticamente todos Queryable
e Enumerable
métodos e métodos de extensão ... O que há com isso?
Respostas:
Embora
Predicate
tenha sido introduzido ao mesmo tempo queList<T>
eArray<T>
, no .net 2.0, os diferentesFunc
eAction
variantes vêm do .net 3.5.Portanto, esses
Func
predicados são usados principalmente para consistência nos operadores LINQ. A partir do .net 3.5, sobre o usoFunc<T>
eAction<T>
a diretriz declara :fonte
Eu já me perguntei isso antes. Eu gosto do
Predicate<T>
delegado - é legal e descritivo. No entanto, você precisa considerar as sobrecargas deWhere
:Isso permite que você filtre com base no índice da entrada também. Isso é legal e consistente, ao passo que:
não seria.
fonte
Where
método de extensão épredicate
. Heh = P.Certamente, o motivo real para usar em
Func
vez de um delegado específico é que o C # trata delegados declarados separadamente como tipos totalmente diferentes.Embora
Func<int, bool>
ePredicate<int>
ambos têm os tipos de argumento e de retorno idênticos, eles não são atribuição compatível. Portanto, se todas as bibliotecas declarassem seu próprio tipo de delegado para cada padrão de delegado, essas bibliotecas não seriam capazes de interoperar a menos que o usuário insira delegados "em ponte" para realizar conversões.Ao incentivar todos a usar o Func, a Microsoft espera que isso alivie o problema de tipos de delegados incompatíveis. Os delegados de todos jogam bem juntos, porque eles serão correspondidos com base em seus tipos de parâmetro / retorno.
Não resolve todos os problemas, porque
Func
(eAction
) não podem terout
ouref
parâmetros, mas esses são menos usados.Atualização: nos comentários Svish diz:
Sim, desde que o seu programa atribua apenas métodos aos delegados, como na primeira linha da minha
Main
função. O compilador silenciosamente gera código para um novo objeto delegado que encaminha para o método. Portanto, na minhaMain
função, eu poderia mudarx1
para ser do tipoExceptionHandler2
sem causar problemas.No entanto, na segunda linha, tento atribuir o primeiro delegado a outro delegado. Mesmo pensando que o segundo tipo de delegado tem exatamente o mesmo parâmetro e tipos de retorno, o compilador dá erro
CS0029: Cannot implicitly convert type 'ExceptionHandler1' to 'ExceptionHandler2'
.Talvez isso torne mais claro:
Meu método
IsNegative
é uma coisa perfeitamente boa para atribuir às variáveisp
ef
, desde que eu o faça diretamente. Mas não posso atribuir uma dessas variáveis à outra.fonte
Func<T, bool>
ouPredicate<T>
ao invés de ter o tipo inferido pelo compilador.O conselho (em 3.5 e acima) é usar o
Action<...>
eFunc<...>
- para o "por quê?" - uma vantagem é que "Predicate<T>
" só tem sentido se você souber o que "predicado" significa - caso contrário, você precisa procurar no navegador de objetos (etc) para encontrar a assinatura.Por outro lado,
Func<T,bool>
segue um padrão padrão; Eu posso dizer imediatamente que esta é uma função que recebeT
e retorna umbool
- não precisa entender nenhuma terminologia - apenas aplique meu teste de verdade.Para "predicado", isso pode ter sido bom, mas agradeço a tentativa de padronização. Também permite muita paridade com os métodos relacionados nessa área.
fonte