Пояснення функції


89

Мені було цікаво, чи хтось може пояснити, що Func<int, string>таке і як це використовується, на явних прикладах.

Відповіді:


145

Ви загалом знайомі з делегатами? У мене є сторінка про делегатів та події, яка може допомогти, якщо ні, хоча вона більше спрямована на пояснення відмінностей між ними.

Func<T, TResult>є лише загальним делегатом - з’ясуйте, що це означає в будь-якій конкретній ситуації, замінивши параметри типу ( Tі TResult) на відповідні аргументи типу ( intі string) в декларації. Я також перейменував його, щоб уникнути плутанини:

string ExpandedFunc(int x)

Іншими словами, Func<int, string>це делегат, який представляє функцію, яка приймає intаргумент і повертає a string.

Func<T, TResult>часто використовується в LINQ як для проекцій, так і для предикатів (в останньому випадку TResultзавжди bool). Наприклад, ви можете використовувати a Func<int, string>для проектування послідовності цілих чисел у послідовність рядків. Лямбда-вирази зазвичай використовуються в LINQ для створення відповідних делегатів:

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

Результат:

Value=3
Value=7
Value=10

3
"Іншими словами, це делегат, який представляє функцію, яка приймає аргумент int і повертає рядок." Щоб уникнути плутанини для інших, я уточню, що ви тут говорите про Func <int, string>, а не про Func <T, TResult>. Очевидно, якщо ви розумієте загальні типи та делегатів, але для тих, хто цього не робить, Func <int, string> може делегувати функцію, яка приймає аргумент int і повертає рядок.
Справжній Напстер

Пояснить, коли я знову буду на ПК.
Джон Скіт,

2
Я думаю, це насправді не так зрозуміло, як опис та приклад MSDN. Я також думаю, що вам слід додати інформацію про те, як останній параметр типу є типом повернення - уточнюючи, що Func <int, int, string> повертає рядок і займає 2 ints. Це допомагає прояснити. Нічого особистого - я просто не думав, що це досить ясно.
TheSoftwareJedi

11
Отже, ви збираєтесь подати голос за кожну відповідь, яку ви вважаєте не такою корисною, як ваша улюблена? Як ви вважаєте, чи ця відповідь активно не допомагає ? Чи вважаєте ви, що, мабуть, більш ніж один погляд на речі може бути не поганою ідеєю?
Джон Скіт,

8
@TheSoftwareJedi: Ні, звичайно, немає причин , щоб взяти downvote особисто - той факт , що ви зробили downvote з особистих причин в суботу , а потім просто трапилося прийти в цю тему після того, як ми мали довгу дискусію по електронній пошті про відповідному поведінці це абсолютно випадково, чи не так?
Джон Скіт,

40

A Func<int, string>їсть ints і повертає рядки. Отже, що їсть ints і повертає рядки? Як щодо цього ...

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

Там я просто створив функцію, яка їсть ints і повертає рядки. Як би я цим скористався?

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"

Я знаю, не дуже сексуально, але це проста ідея, на якій базується багато хитрощів. Тепер давайте використовувати замість цього 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

Замість того, щоб викликати IntAsString для кожного члена, я створив посилання на нього з назвою fnc (ці посилання на методи називаються делегатами ) і використовував це замість цього. (Пам'ятайте, fnc їсть ints і повертає рядки).

Цей приклад не дуже сексуальний, але маса розумних речей, які ви побачите, базується на простому уявленні про функції, делегатів та методи розширення .

Один з найкращих праймерів з цього матеріалу, який я бачив, тут . У нього є набагато більше реальних прикладів. :)


@Therealnapster мені теж подобається, але твоє ім'я мені подобається більше.
BKSpurgeon

27

Це делегат, який приймає його intяк параметр і повертає значення типу string.

Ось приклад його використання:

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
Дякую Ендрю. Ви мали на увазі написати функцію (1) замість рядка (1)?
zSynopsis

1

Func<int, string>приймає параметр значення int і повертає значення рядка. Ось приклад, коли додатковий метод підтримки непотрібний.

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

ПРИМІТКА: Останній тип об'єкта у Func (тобто "рядок" у цьому прикладі) - це тип повернення функцій (тобто не обмежується примітивами, а будь-яким об’єктом). Отже, Func<int, bool, float>приймає параметри int та bool і повертає плаваюче значення.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.