Wyjaśnienie funkcji Func


89

Zastanawiałem się, czy ktoś mógłby wyjaśnić, co to Func<int, string>jest i jak jest używane, z jasnymi przykładami.

Odpowiedzi:


145

Czy ogólnie znasz delegatów? Mam stronę o delegatach i wydarzeniach, która może pomóc, jeśli nie, chociaż jest bardziej nastawiona na wyjaśnienie różnic między nimi.

Func<T, TResult>jest tylko delegatem ogólnym - dowiedz się, co to oznacza w dowolnej konkretnej sytuacji, zastępując parametry typu ( Ti TResult) odpowiednimi argumentami typu ( inti string) w deklaracji. Zmieniłem też jego nazwę, aby uniknąć nieporozumień:

string ExpandedFunc(int x)

Innymi słowy, Func<int, string>jest delegatem, który reprezentuje funkcję pobierającą intargument i zwracającą string.

Func<T, TResult>jest często używany w LINQ, zarówno dla prognoz, jak i predykatów (w tym drugim przypadku TResultjest zawsze bool). Na przykład można użyć a, Func<int, string>aby zaprojektować sekwencję liczb całkowitych na sekwencję ciągów. Wyrażenia lambda są zwykle używane w LINQ do tworzenia odpowiednich delegatów:

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

Wynik:

Value=3
Value=7
Value=10

3
„Innymi słowy, jest to delegat, który reprezentuje funkcję pobierającą argument int i zwracającą ciąg”. Aby uniknąć nieporozumień dla innych, wyjaśnię, że mówisz tutaj o Func <int, string>, a nie o Func <T, TResult>. Jest oczywiste, jeśli rozumiesz typy ogólne i delegatów, ale dla tych, którzy tego nie robią, funkcja Func <int, string> jest delegowana przez kan do funkcji, która przyjmuje argument int i zwraca ciąg.
— Prawdziwy napster

Wyjaśni, kiedy wrócę na komputer później.
— Jon Skeet

2
Myślę, że to faktycznie nie jest tak jasne, jak opis i przykład MSDN. Myślę również, że powinieneś dodać informacje o tym, jak ostatni parametr typu jest typem zwracanym - wyjaśniając, że Func <int, int, string> zwraca ciąg i przyjmuje 2 ints. To pomaga wyjaśnić. Nic osobistego - po prostu nie sądziłem, że było to wystarczająco jasne.
— TheSoftwareJedi

11
Czy zamierzasz więc zlekceważyć każdą odpowiedź, którą uważasz za nie tak pomocną, jak twoja ulubiona? Czy myślisz, że ta odpowiedź jest aktywnie nieprzydatna ? Czy uważasz, że być może posiadanie więcej niż jednego sposobu patrzenia na rzeczy może nie być złym pomysłem?
— Jon Skeet

8
@TheSoftwareJedi: Nie, oczywiście, nie ma powodu, aby wziąć downvote osobiście - fakt, że zrobił downvote z powodów osobistych w sobotę, a potem po prostu się przyjść do tego wątku po byliśmy po długiej dyskusji na temat właściwego zachowania email jest całkowicie przypadkowe, prawda?
— Jon Skeet

40

A Func<int, string>zjada ints i zwraca stringi. Więc co zjada int i zwraca ciągi? Co powiesz na to ...

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

Tam właśnie stworzyłem funkcję, która zjada ints i zwraca ciągi. Jak bym tego użył?

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"

Wiem, że niezbyt seksowne, ale na tym polega prosta idea, na której opiera się wiele sztuczek. Teraz użyjmy zamiast tego 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

Zamiast wywoływać IntAsString na każdym elemencie członkowskim, utworzyłem odwołanie do niego o nazwie fnc (te odwołania do metod nazywane są delegatami ) i zamiast tego użyłem tego. (Pamiętaj, że fnc zjada wartości int i zwraca ciągi znaków).

Ten przykład nie jest zbyt seksowny, ale mnóstwo sprytnych rzeczy, które zobaczysz, opiera się na prostej idei funkcji, delegatów i metod rozszerzających .

Jeden z najlepszych podkładów na ten temat, jaki widziałem, jest tutaj . Ma o wiele więcej prawdziwych przykładów. :)


@Therealnapster Ja też to lubię, ale bardziej podoba mi się Twoje imię.
— BKSpurgeon,

28

Jest to delegat, który przyjmuje je intjako parametr i zwraca wartość typu string.

Oto przykład jego użycia:

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

3
Dzięki Andrew. Czy chodziło Ci o napisanie func (1) zamiast bar (1)?
— zSynopsis

1

Func<int, string>akceptuje parametr wartości int i zwraca wartość ciągu. Oto przykład, w którym dodatkowa metoda wspomagająca nie jest konieczna.

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

UWAGA: Ostatnim typem obiektu w Func (tj. „String” w tym przykładzie) jest typ zwracany przez funkcje (tj. Nie jest ograniczony do prymitywów, ale dowolnego obiektu). Dlatego Func<int, bool, float>akceptuje parametry wartości typu int i bool i zwraca wartość zmiennoprzecinkową.

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.