Інші вже вказували, що існує нескінченно багато можливих типів делегатов, які ви могли б мати на увазі; що таке особливий , Func
що він заслуговує того, щоб бути за замовчуванням замість Predicate
або Action
будь-якої іншої можливості? А для лямбдасів, чому очевидно, що наміром є вибір форми делегата, а не форма дерева виразів?
Але ми могли б сказати, що Func
це особливе, і що висновок типу лямбда або анонімного методу є функцією чогось. У нас все ще будуть усілякі проблеми. Які типи хотіли б зробити для наступних випадків?
var x1 = (ref int y)=>123;
Немає жодного Func<T>
типу, який би відповідав на щось.
var x2 = y=>123;
Ми не знаємо тип формального параметра, хоча ми знаємо повернення. (Або ми? Чи повернення int? Long? Short? Byte?)
var x3 = (int y)=>null;
Ми не знаємо тип повернення, але він не може бути недійсним. Тип повернення може бути будь-яким опорним типом або будь-яким типом нульового значення.
var x4 = (int y)=>{ throw new Exception(); }
Знову ж таки, ми не знаємо тип повернення, і цього разу він може бути недійсним.
var x5 = (int y)=> q += y;
Чи призначено це бути лямбда-поверненням, що повертається нічим, або чимось, що повертає значення, яке було призначено q? Обидва є законними; що нам вибрати?
Тепер, ви можете сказати, ну просто не підтримуйте жодну з цих функцій. Просто підтримуйте "звичайні" випадки, коли типи можна опрацювати. Це не допомагає. Як це полегшує моє життя? Якщо функція спрацьовує іноді, а інколи виходить з ладу, мені все одно доведеться написати код, щоб виявити всі ці ситуації з відмовою і дати змістовне повідомлення про помилку для кожного. Нам залишається конкретизувати всю цю поведінку, документувати її, писати на неї тести тощо. Це дуже дорога функція, яка економить користувача, можливо, півдесятка натискань клавіш. У нас є кращі способи додати цінність мові, ніж витрачати багато часу на написання тестових випадків для функції, яка не працює половину часу і майже не дає користі у випадках, коли вона працює.
Ситуація, коли це насправді корисно:
var xAnon = (int y)=>new { Y = y };
тому що для цієї речі не існує "розмовного" типу. Але у нас ця проблема постійно, і ми просто використовуємо висновок типу методу для виведення типу:
Func<A, R> WorkItOut<A, R>(Func<A, R> f) { return f; }
...
var xAnon = WorkItOut((int y)=>new { Y = y });
і тепер умовивід типу методу працює, що таке тип func.
Func<>
приймає до 16 аргументів.