É apenas um atalho para delegados com uma assinatura específica. Para entender completamente as respostas abaixo, você precisará entender os delegados ;-)
Theo Lenndorff
2
Na resposta de @Oded dizIf you have a function that needs to return different types, depending on the parameters, you can use a Func delegate, specifying the return type.
LCJ
Respostas:
76
Func<T> é um tipo de delegado predefinido para um método que retorna algum valor do tipo T .
Em outras palavras, você pode usar esse tipo para fazer referência a um método que retorna algum valor de T. Por exemplo
Mas também pode representar uma função estática de um argumento =)
Ark-kun
2
@ Ark-kun não, isso não é correto. A definição de Func<T>é delegate TResult Func<out TResult>(). Sem argumentos. Func<T1, T2>seria uma função que leva um argumento.
Brian Rasmussen
4
Não, estou certo. static int OneArgFunc(this string i) { return 42; }Func<int> f = "foo".OneArgFunc;. =)
Ark-kun
1
Esse é um método de extensão especial.
Brian Rasmussen
A única coisa especial sobre isso é o Extensionatributo que só é lido pelos compiladores C # / VB.Net, não CLR. Basicamente, os métodos de instância (ao contrário das funções estáticas) têm um 0º parâmetro oculto "este". Portanto, o método de instância de 1 argumento é muito semelhante à função estática de 2 argumentos. Então, temos delegados que armazenam o objeto de destino e o ponteiro de função . Os delegados podem armazenar o primeiro argumento no destino ou não fazer isso.
Ark-kun
87
Pense nisso como um espaço reservado. Pode ser muito útil quando você tem um código que segue um certo padrão, mas não precisa estar vinculado a nenhuma funcionalidade específica.
Por exemplo, considere o Enumerable.Selectmétodo de extensão.
O padrão é: para cada item em uma sequência, selecione algum valor desse item (por exemplo, uma propriedade) e crie uma nova sequência consistindo desses valores.
O espaço reservado é: alguma função de seletor que realmente obtém os valores para a sequência descrita acima.
Este método assume uma Func<T, TResult>função concreta em vez de qualquer. Isso permite que seja usado em qualquer contexto onde o padrão acima se aplique.
Por exemplo, digamos que tenho um List<Person>e quero apenas o nome de todas as pessoas da lista. Eu posso fazer isso:
var names = people.Select(p => p.Name);
Ou diga que eu quero o idade de cada pessoa:
var ages = people.Select(p => p.Age);
De imediato, você pode ver como consegui alavancar o mesmo código que representa um padrão (com Select) com dois funções diferentes ( p => p.Nameep => p.Age ).
A alternativa seria escrever uma versão diferente de Selectcada vez que você quisesse varrer uma sequência para um tipo diferente de valor. Portanto, para obter o mesmo efeito acima, eu precisaria:
// Presumably, the code inside these two methods would look almost identical;// the only difference would be the part that actually selects a value// based on a Person.var names =GetPersonNames(people);var ages =GetPersonAges(people);
Com um delegado atuando como espaço reservado, eu me liberto de ter que escrever o mesmo padrão repetidamente em casos como este.
Em seguida, você deve criar a classe PrintListToConsole<T>que pega a interface criada anteriormente e a usa sobre cada elemento da lista.
classPrintListToConsole<T>{privatePrintListConsoleRender<T> _renderer;publicvoidSetRenderer(PrintListConsoleRender<T> r){// this is the point where I can personalize the render mechanism
_renderer = r;}publicvoidPrintToConsole(List<T>list){foreach(var item inlist){Console.Write(_renderer.Render(item));}}}
O desenvolvedor que precisa usar seu componente deve:
Dentro do componente, você define um parâmetro do tipo Func<T,String>que representa uma interface de uma função que recebe um parâmetro de entrada do tipo T e retorna uma string (a saída para o console)
classPrintListToConsole<T>{privateFunc<T,String> _renderFunc;publicvoidSetRenderFunc(Func<T,String> r){// this is the point where I can set the render mechanism
_renderFunc = r;}publicvoidPrint(List<T>list){foreach(var item inlist){Console.Write(_renderFunc(item));}}}
Quando o desenvolvedor usa seu componente, ele simplesmente passa para o componente a implementação do Func<T, String>tipo, que é uma função que cria a saída para o console.
classProgram{staticvoidMain(string[] args){varlist=newList<int>{1,2,3};// should be a list as the method signature expectsvar printer =newPrintListToConsole<int>();
printer.SetRenderFunc((o)=>"Number:"+ o);
printer.Print(list);string result =Console.ReadLine();}}
Func<T>permite definir uma interface de método genérico em tempo real.
Você define qual é o tipo de entrada e qual é o tipo de saída. Simples e conciso.
Obrigado por postar este Marco. Isso realmente me ajudou. Eu tenho tentado entender o func por um tempo e também usá-lo ativamente na minha programação. Este exemplo limpará o caminho. Tive que adicionar o método StampaFunc, pois ele foi deixado de fora no código original, o que impediu sua exibição.
Siwoku Adeola
1
Acho que falta uma linha no exemplo Func, onde está a chamada para a função de impressão ou StampaFunc?
Bashar Abu Shamaa
11
Func<T1,R>e os outros predefinidos genéricos Funcdelegados ( Func<T1,T2,R>, Func<T1,T2,T3,R>e outros) são representantes genéricos que retornam o tipo do último parâmetro genérico.
Se você tem uma função que precisa retornar diferentes tipos, dependendo dos parâmetros, você pode usar um Funcdelegado, especificando o tipo de retorno.
É apenas um delegado genérico predefinido. Usando-o, você não precisa declarar todos os delegados. Existe outro delegado predefinido Action<T, T2...>, que é o mesmo, mas retorna vazio.
Talvez não seja tarde demais para acrescentar algumas informações.
Soma:
O Func é um delegado personalizado definido no namespace System que permite apontar para um método com a mesma assinatura (como fazem os delegados), usando 0 a 16 parâmetros de entrada e que deve retornar algo.
If you have a function that needs to return different types, depending on the parameters, you can use a Func delegate, specifying the return type.
Respostas:
Func<T>
é um tipo de delegado predefinido para um método que retorna algum valor do tipoT
.Em outras palavras, você pode usar esse tipo para fazer referência a um método que retorna algum valor de
T
. Por exemplopode ser referenciado assim
fonte
Func<T>
édelegate TResult Func<out TResult>()
. Sem argumentos.Func<T1, T2>
seria uma função que leva um argumento.static int OneArgFunc(this string i) { return 42; }
Func<int> f = "foo".OneArgFunc;
. =)Extension
atributo que só é lido pelos compiladores C # / VB.Net, não CLR. Basicamente, os métodos de instância (ao contrário das funções estáticas) têm um 0º parâmetro oculto "este". Portanto, o método de instância de 1 argumento é muito semelhante à função estática de 2 argumentos. Então, temos delegados que armazenam o objeto de destino e o ponteiro de função . Os delegados podem armazenar o primeiro argumento no destino ou não fazer isso.Pense nisso como um espaço reservado. Pode ser muito útil quando você tem um código que segue um certo padrão, mas não precisa estar vinculado a nenhuma funcionalidade específica.
Por exemplo, considere o
Enumerable.Select
método de extensão.Este método assume uma
Func<T, TResult>
função concreta em vez de qualquer. Isso permite que seja usado em qualquer contexto onde o padrão acima se aplique.Por exemplo, digamos que tenho um
List<Person>
e quero apenas o nome de todas as pessoas da lista. Eu posso fazer isso:Ou diga que eu quero o idade de cada pessoa:
De imediato, você pode ver como consegui alavancar o mesmo código que representa um padrão (com
Select
) com dois funções diferentes (p => p.Name
ep => p.Age
).A alternativa seria escrever uma versão diferente de
Select
cada vez que você quisesse varrer uma sequência para um tipo diferente de valor. Portanto, para obter o mesmo efeito acima, eu precisaria:Com um delegado atuando como espaço reservado, eu me liberto de ter que escrever o mesmo padrão repetidamente em casos como este.
fonte
Func<T1, T2, ..., Tn, Tr>
representa uma função, que recebe argumentos (T1, T2, ..., Tn) e retorna Tr.Por exemplo, se você tem uma função:
Você pode salvá-lo como algum tipo de variável de função:
E então use exatamente como usaria o sqr:
etc.
Porém, lembre-se de que é um delegado; para informações mais avançadas, consulte a documentação.
fonte
Acho
Func<T>
muito útil quando crio um componente que precisa ser personalizado "na hora".Veja este exemplo muito simples: um
PrintListToConsole<T>
componente.Um objeto muito simples que imprime essa lista de objetos no console. Você deseja permitir que o desenvolvedor que o utiliza personalize a saída.
Por exemplo, você deseja permitir que ele defina um tipo específico de formato de número e assim por diante.
Sem Func
Primeiro, você deve criar uma interface para uma classe que recebe a entrada e produz a string para imprimir no console.
Em seguida, você deve criar a classe
PrintListToConsole<T>
que pega a interface criada anteriormente e a usa sobre cada elemento da lista.O desenvolvedor que precisa usar seu componente deve:
implementar a interface
passe a aula real para o
PrintListToConsole
Usar Func é muito mais simples
Dentro do componente, você define um parâmetro do tipo
Func<T,String>
que representa uma interface de uma função que recebe um parâmetro de entrada do tipo T e retorna uma string (a saída para o console)Quando o desenvolvedor usa seu componente, ele simplesmente passa para o componente a implementação do
Func<T, String>
tipo, que é uma função que cria a saída para o console.Func<T>
permite definir uma interface de método genérico em tempo real. Você define qual é o tipo de entrada e qual é o tipo de saída. Simples e conciso.fonte
Func<T1,R>
e os outros predefinidos genéricosFunc
delegados (Func<T1,T2,R>
,Func<T1,T2,T3,R>
e outros) são representantes genéricos que retornam o tipo do último parâmetro genérico.Se você tem uma função que precisa retornar diferentes tipos, dependendo dos parâmetros, você pode usar um
Func
delegado, especificando o tipo de retorno.fonte
É apenas um delegado genérico predefinido. Usando-o, você não precisa declarar todos os delegados. Existe outro delegado predefinido
Action<T, T2...>
, que é o mesmo, mas retorna vazio.fonte
Talvez não seja tarde demais para acrescentar algumas informações.
Soma:
O Func é um delegado personalizado definido no namespace System que permite apontar para um método com a mesma assinatura (como fazem os delegados), usando 0 a 16 parâmetros de entrada e que deve retornar algo.
Nomenclatura e como usar:
Definição:
Onde é usado:
É usado em expressões lambda e métodos anônimos.
fonte