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


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.