Explication de Func

89

Je me demandais si quelqu'un pourrait expliquer ce que Func<int, string>c'est et comment il est utilisé avec des exemples clairs.

zSynopsis
la source

Réponses:

145

Connaissez-vous les délégués en général? J'ai une page sur les délégués et les événements qui peuvent aider sinon, bien qu'elle soit plus orientée vers l'explication des différences entre les deux.

Func<T, TResult>est juste un délégué générique - déterminez ce que cela signifie dans une situation particulière en remplaçant les paramètres de type ( Tet TResult) par les arguments de type correspondants ( intet string) dans la déclaration. Je l'ai également renommé pour éviter toute confusion:

string ExpandedFunc(int x)

En d'autres termes, Func<int, string>est un délégué qui représente une fonction prenant un intargument et retournant un string.

Func<T, TResult>est souvent utilisé dans LINQ, à la fois pour les projections et les prédicats (dans ce dernier cas, TResultest toujours bool). Par exemple, vous pouvez utiliser a Func<int, string>pour projeter une séquence d'entiers dans une séquence de chaînes. Les expressions Lambda sont généralement utilisées dans LINQ pour créer les délégués appropriés:

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);
}

Résultat:

Value=3
Value=7
Value=10
Jon Skeet
la source
3
"En d'autres termes, c'est un délégué qui représente une fonction prenant un argument int et renvoyant une chaîne." Juste pour éviter toute confusion pour les autres, je vais clarifier que vous parlez de Func <int, string> ici et non de Func <T, TResult>. C'est évident si vous comprenez les types génériques et les délégués, mais pour ceux qui ne le font pas, c'est Func <int, string> qui peut déléguer à une fonction qui prend un argument int et renvoie une chaîne.
Le vrai napster
Clarifierai quand je serai de retour sur un PC plus tard.
Jon Skeet
2
Je pense que ce n'est pas aussi clair que la description et l'exemple de MSDN. Je pense également que vous devriez ajouter des informations sur la façon dont le dernier paramètre de type est le type de retour - en précisant que Func <int, int, string> renvoie une chaîne et prend 2 ints. Cela aide à clarifier. Rien de personnel - je ne pensais pas que c'était assez clair.
TheSoftwareJedi
11
Alors, allez-vous décliner chaque réponse que vous jugez pas aussi utile que votre préférée? Cette réponse est-elle vraiment inutile , pensez-vous? Pensez-vous qu'avoir plus d'une façon de voir les choses n'est peut-être pas une mauvaise idée?
Jon Skeet
8
@TheSoftwareJedi: Non, bien sûr, aucune raison de prendre votre downvote personnellement - le fait que vous avez fait downvote pour des raisons personnelles le samedi et puis juste arrivé à venir dans ce fil après que nous avons eu une longue discussion sur le courrier électronique sur le comportement approprié est entièrement une coïncidence, n'est-ce pas?
Jon Skeet
40

A Func<int, string>mange des entiers et renvoie des chaînes. Alors, qu'est-ce qui mange des entiers et renvoie des chaînes? Que dis-tu de ça ...

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

Là, je viens de créer une fonction qui mange des ints et renvoie des chaînes. Comment l'utiliserais-je?

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"

Pas très sexy, je sais, mais c'est l'idée simple sur laquelle beaucoup de trucs sont basés. Maintenant, utilisons un Func à la place.

Func<int, string> fnc = IntAsString;

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

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

Au lieu d'appeler IntAsString sur chaque membre, j'ai créé une référence à celui-ci appelée fnc (ces références aux méthodes sont appelées délégués ) et l' ai utilisée à la place. (N'oubliez pas que fnc mange des entiers et renvoie des chaînes).

Cet exemple n'est pas très sexy, mais une tonne de choses intelligentes que vous verrez est basée sur l'idée simple de fonctions, de délégués et de méthodes d'extension .

L'une des meilleures amorces sur ce truc que j'ai vues est ici . Il a beaucoup plus d'exemples réels. :)

JP Alioto
la source
@Therealnapster je l'aime aussi mais j'aime plus ton nom.
BKSpurgeon
27

C'est un délégué qui en prend un intcomme paramètre et renvoie une valeur de type string.

Voici un exemple de son utilisation:

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
la source
3
Merci Andrew. Vouliez-vous écrire func (1) au lieu de bar (1)?
zSynopsis
1

Func<int, string>accepte un paramètre de valeur int et renvoie une valeur de chaîne. Voici un exemple où une méthode de prise en charge supplémentaire n'est pas nécessaire.

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);

REMARQUE: Le dernier type d'objet dans Func (c'est-à-dire "chaîne" dans cet exemple) est le type de retour des fonctions (c'est-à-dire non limité aux primitives, mais à n'importe quel objet). Par conséquent, Func<int, bool, float>accepte les paramètres de valeur int et booléenne et renvoie une valeur flottante.

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
la source