У меня такой код:
Func<string, bool> comparer = delegate(string value) {
return value != "0";
};
Однако следующее не компилируется:
var comparer = delegate(string value) {
return value != "0";
};
Почему компилятор не может понять, что это Func<string, bool>
? Он принимает один строковый параметр и возвращает логическое значение. Вместо этого он дает мне ошибку:
Невозможно назначить анонимный метод неявно типизированной локальной переменной.
У меня есть одно предположение: если бы версия var была скомпилирована , ей не хватало бы согласованности, если бы у меня было следующее:
var comparer = delegate(string arg1, string arg2, string arg3, string arg4, string arg5) {
return false;
};
Вышесказанное не имеет смысла, поскольку Func <> допускает только до 4 аргументов (в .NET 3.5, что я и использую). Возможно, кто-нибудь сможет прояснить проблему. Спасибо.
Func<>
принять до 16 аргументов.Func<string, bool>
?Converter<string, bool>
Для меня это похоже на!Dim comparer = Function(value$) value <> "0"
Ответы:
Другие уже указывали, что существует бесконечно много возможных типов делегатов, которые вы могли иметь в виду; Что такого особенного в том,
Func
что оно заслуживает того, чтобы быть по умолчанию вместоPredicate
илиAction
или любой другой возможности? А для лямбда-выражений, почему очевидно, что намерение состоит в том, чтобы выбрать форму делегата, а не форму дерева выражения?Но мы могли бы сказать, что
Func
это особенное, и что предполагаемый тип лямбда или анонимного метода - это Func чего-то. У нас по-прежнему будут всевозможные проблемы. Какие типы вы хотели бы вывести в следующих случаях?var x1 = (ref int y)=>123;
Нет такого
Func<T>
типа, который мог бы что-либо использовать.var x2 = y=>123;
Мы не знаем тип формального параметра, но знаем возвращаемый результат. (Или мы? Возвращаемый int? Длинный? Короткий? Байт?)
var x3 = (int y)=>null;
Мы не знаем возвращаемого типа, но он не может быть недействительным. Тип возврата может быть любым ссылочным типом или любым типом значения, допускающим значение 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 });
и теперь вывод типа метода определяет, что это за тип функции.
источник
Только Эрик Липперт знает наверняка, но я думаю, это потому, что сигнатура типа делегата не определяет тип однозначно.
Рассмотрим свой пример:
var comparer = delegate(string value) { return value != "0"; };
Вот два возможных вывода о том, что
var
должно быть:Predicate<string> comparer = delegate(string value) { return value != "0"; }; // okay Func<string, bool> comparer = delegate(string value) { return value != "0"; }; // also okay
Какой из них должен сделать вывод компилятор? Нет веских причин выбирать то или другое. И хотя
Predicate<T>
функционально a эквивалентно aFunc<T, bool>
, они по-прежнему являются разными типами на уровне системы типов .NET. Таким образом, компилятор не может однозначно определить тип делегата и должен не выполнить вывод типа.источник
У Эрика Липперта есть старый пост об этом, где он говорит
источник
Разные делегаты считаются разными типами. например,
Action
отличается отMethodInvoker
, и экземплярAction
не может быть назначен переменной типаMethodInvoker
.Итак, учитывая анонимный делегат (или лямбда)
() => {}
, это типAction
илиMethodInvoker
? Компилятор не может сказать.Точно так же, если я объявлю тип делегата, принимающий
string
аргумент и возвращающий abool
, как компилятор узнает, что вам действительно нуженFunc<string, bool>
тип делегата вместо моего? Он не может определить тип делегата.источник
Следующие пункты взяты из MSDN относительно неявно типизированных локальных переменных:
Справка MSDN: неявно типизированные локальные переменные
Учитывая следующее относительно анонимных методов:
Ссылка MSDN: анонимные методы
Я подозреваю, что, поскольку анонимный метод может иметь разные сигнатуры метода, компилятор не может правильно определить, какой тип будет наиболее подходящим для назначения.
источник
Мой пост не отвечает на фактический вопрос, но он отвечает на основной вопрос:
«Как мне избежать необходимости печатать какой-нибудь унылый типаж
Func<string, string, int, CustomInputType, bool, ReturnType>
?» [1]Как я и ленивый программист, я экспериментировал с использованием
Func<dynamic, object>
-, которое принимает единственный входной параметр и возвращает объект.Для нескольких аргументов вы можете использовать это так:
dynamic myParams = new ExpandoObject(); myParams.arg0 = "whatever"; myParams.arg1 = 3; Func<dynamic, object> y = (dynObj) => { return dynObj.arg0.ToUpper() + (dynObj.arg1 * 45); //screw type casting, amirite? }; Console.WriteLine(y(myParams));
Совет: вы можете использовать
Action<dynamic>
если вам не нужно возвращать объект.Да, я знаю, что это, вероятно, противоречит вашим принципам программирования, но это имеет смысл для меня и, возможно, некоторых программистов Python.
Я новичок в делегатах ... просто хотел поделиться тем, что узнал.
[1] Предполагается, что вы не вызываете метод, который требует предопределенного
Func
параметра в качестве параметра, и в этом случае вам придется ввести эту уродливую строку: /источник
Как насчет этого?
var item = new { toolisn = 100, LangId = "ENG", toolPath = (Func<int, string, string>) delegate(int toolisn, string LangId) { var path = "/Content/Tool_" + toolisn + "_" + LangId + "/story.html"; return File.Exists(Server.MapPath(path)) ? "<a style=\"vertical-align:super\" href=\"" + path + "\" target=\"_blank\">execute example</a> " : ""; } }; string result = item.toolPath(item.toolisn, item.LangId);
источник