Explicação de Func

89

Gostaria de saber se alguém poderia explicar o que Func<int, string>é e como é usado com alguns exemplos claros.

zSynopsis
fonte

Respostas:

145

Você está familiarizado com os delegados em geral? Tenho uma página sobre delegados e eventos que pode ajudar se não, embora seja mais voltada para explicar as diferenças entre os dois.

Func<T, TResult>é apenas um delegado genérico - descubra o que isso significa em qualquer situação particular, substituindo os parâmetros de tipo ( Te TResult) pelos argumentos de tipo correspondentes ( inte string) na declaração. Eu também o renomei para evitar confusão:

string ExpandedFunc(int x)

Em outras palavras, Func<int, string>é um delegado que representa uma função recebendo um intargumento e retornando um string.

Func<T, TResult>é freqüentemente usado no LINQ, tanto para projeções quanto para predicados (no último caso, TResulté sempre bool). Por exemplo, você pode usar a Func<int, string>para projetar uma sequência de inteiros em uma sequência de strings. As expressões lambda geralmente são usadas no LINQ para criar os delegados relevantes:

Func<int, string> projection = x => "Value=" + x;
int[] values = { 3, 7, 10 };
var strings = values.Select(projection);

foreach (string s in strings)
{
    Console.WriteLine(s);
}

Resultado:

Value=3
Value=7
Value=10
Jon Skeet
fonte
3
"Em outras palavras, é um delegado que representa uma função recebendo um argumento int e retornando uma string." Apenas para evitar confusão para os outros, vou esclarecer que você está falando sobre Func <int, string> aqui e não Func <T, TResult>. É óbvio se você entende tipos e delegados genéricos, mas para aqueles que não entendem, é Func <int, string> que pode delegar para uma função que recebe um argumento int e retorna uma string.
O verdadeiro napster
Esclarecerá quando estiver de volta em um PC mais tarde.
Jon Skeet
2
Acho que isso não é tão claro quanto a descrição e o exemplo do MSDN. Eu também acho que você deve adicionar informações sobre como o último parâmetro de tipo é o tipo de retorno - esclarecendo que Func <int, int, string> retorna string e leva 2 ints. Isso ajuda a esclarecer. Nada pessoal - só não achei que fosse claro o suficiente.
TheSoftwareJedi
11
Então, você vai rebaixar a votação de todas as respostas que considera não serem tão úteis quanto suas favoritas em particular? Esta resposta é ativamente inútil , você acha? Você acha que talvez ter mais de uma maneira de ver as coisas não seja uma má ideia?
Jon Skeet
8
@TheSoftwareJedi: Não, é claro, não há razão para tomar o seu downvote pessoalmente - o fato de que você fez downvote por motivos pessoais no sábado e depois é só aconteceu para vir a este tópico depois de termos tido uma longa discussão sobre e-mail sobre o comportamento adequado é inteiramente coincidência, não é?
Jon Skeet
40

A Func<int, string>come ints e retorna strings. Então, o que come ints e retorna strings? Que tal agora ...

public string IntAsString( int i )
{
  return i.ToString();
}

Lá, acabei de criar uma função que come ints e retorna strings. Como eu usaria?

var lst = new List<int>() { 1, 2, 3, 4, 5 };
string str = String.Empty;

foreach( int i in lst )
{
  str += IntAsString(i);
}

// str will be "12345"

Não é muito sexy, eu sei, mas essa é a ideia simples na qual muitos truques se baseiam. Agora, vamos usar um Func.

Func<int, string> fnc = IntAsString;

foreach (int i in lst)
{
  str += fnc(i);
}

// str will be "1234512345" assuming we have same str as before

Em vez de chamar IntAsString em cada membro, criei uma referência a ele chamada fnc (essas referências a métodos são chamadas de delegados ) e usei isso. (Lembre-se de que o fnc come ints e retorna strings).

Este exemplo não é muito atraente, mas muitas das coisas inteligentes que você verá são baseadas na ideia simples de funções, delegados e métodos de extensão .

Uma das melhores instruções sobre esse assunto que já vi está aqui . Ele tem muito mais exemplos reais. :)

JP Alioto
fonte
@Therealnapster eu também gosto, mas gosto mais do seu nome.
BKSpurgeon
27

É um delegado que recebe um intcomo parâmetro e retorna um valor do tipo string.

Aqui está um exemplo de seu uso:

using System;

class Program
{
    static void Main()
    {
        Func<Int32, String> func = bar;

        // now I have a delegate which 
        // I can invoke or pass to other
        // methods.
        func(1);
    }

    static String bar(Int32 value)
    {
        return value.ToString();
    }
}
Andrew Hare
fonte
3
Obrigado, Andrew. Você quis dizer escrever func (1) em vez de bar (1)?
zSynopsis
1

Func<int, string>aceita um parâmetro de valor int e retorna um valor de string. Aqui está um exemplo em que um método de suporte adicional é desnecessário.

Func<int, string> GetDogMessage = dogAge =>
        {
            if (dogAge < 3) return "You have a puppy!";
            if (dogAge < 7) return "Strong adult dog!";

            return "Age is catching up with the dog!";
        };

string youngDogMessage = GetDogMessage(2);

NOTA: O último tipo de objeto em Func (ou seja, "string" neste exemplo) é o tipo de retorno das funções (ou seja, não limitado a primitivos, mas a qualquer objeto). Portanto, Func<int, bool, float>aceita os parâmetros de valor int e bool e retorna um valor flutuante.

Func<int, bool, float> WorthlessFunc = (intValue, boolValue) =>
        {
            if(intValue > 100 && boolValue) return 100;

            return 1;
        };
float willReturn1 = WorthlessFunc(21, false);
float willReturn100 = WorthlessFunc(1000, true);

HTH

jts
fonte