Мені було цікаво, чи хтось може пояснити, що Func<int, string>
таке і як це використовується, на явних прикладах.
Відповіді:
Ви загалом знайомі з делегатами? У мене є сторінка про делегатів та події, яка може допомогти, якщо ні, хоча вона більше спрямована на пояснення відмінностей між ними.
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
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 і повертає рядки).
Цей приклад не дуже сексуальний, але маса розумних речей, які ви побачите, базується на простому уявленні про функції, делегатів та методи розширення .
Один з найкращих праймерів з цього матеріалу, який я бачив, тут . У нього є набагато більше реальних прикладів. :)
Це делегат, який приймає його 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();
}
}
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