У вас есть несколько вопросов здесь.(В будущем я бы рекомендовал, если у вас есть несколько вопросов, разделите их на несколько вопросов, а не на одну публикацию с несколькими вопросами; вы, вероятно, получите лучшие ответы.)
Почему можнокомпилятор не выводит параметр типа "int" в:
TryParseExtensions.OrNull(int.TryParse, "2");
Хороший вопрос.Вместо того, чтобы ответить на этот вопрос, я отсылаю вас к моей статье 2007 года, в которой объясняется, почему это не сработало в C # 3.0:
http://blogs.msdn.com/b/ericlippert/archive/2007/11/05/c-3-0-return-type-inference-does-not-work-on-member-groups.aspx
Подводя итог: в сущности, есть чепуха ипроблема с яйцом здесь.Мы должны выполнить разрешение перегрузки для int.TryParse, чтобы определить, какая перегрузка TryParse является предполагаемой (или, если ни одна из них не работает, в чем заключается ошибка.) Разрешение перегрузки всегда пытается вывести из arguments .В этом случае, однако, это именно тот тип аргумента, который мы пытаемся вывести.
Мы могли бы придумать новый алгоритм разрешения перегрузки, который говорит: «Хорошо, если в группе методов только один методзатем выберите этот, даже если мы не знаем, что это за аргументы ", но это кажется слабым.Это кажется плохой идеей для групп методов особого случая, в которых есть только один метод, потому что тогда это наказывает вас за добавление новых перегрузок;это может внезапно стать переломным изменением.
Как видно из комментариев к этой статье, мы получили много хороших отзывов об этом.Лучшая обратная связь была получена в основном «ну, предположим, что вывод типа уже проработал типы всех аргументов, и это возвращаемый тип , который мы пытаемся вывести;В случае, если вы могли бы сделать разрешение перегрузки ".Этот анализ верен, и изменения в этом отношении вошли в C # 4. Я говорил об этом немного больше здесь:
http://blogs.msdn.com/b/ericlippert/archive/2008/05/28/method-type-inference-changes-part-zero.aspx
Правильно ли я понимаю, что методы расширений делаютне быть обнаруженным на типах делегатов, так как я предполагаю, что они на самом деле не относятся к тому типу (но являются «Методом»), который только соответствует сигнатуре делегатов?
Ваша терминология немного не подходит, нотвоя идея верна.Мы не обнаруживаем методы расширения, когда «получатель» - это группа методов .В более общем смысле, мы не обнаруживаем методы расширения, когда получатель является чем-то, что не имеет своего собственного типа, а скорее принимает тип, основанный на его контексте: группы методов, лямбда-выражения, анонимные методы и нулевой литерал - все имеют это свойство.Было бы очень странно сказать null.Whatever()
и вызвать этот метод расширения для String или, что еще более странно, (x=>x+1).Whatever()
и вызвать метод расширения для Func<int, int>
.
Строка спецификации.которое описывает это поведение:
Неявное преобразование идентификатора, ссылки или бокса [должно существовать] из [выражения получателя] в тип первого параметра [...].
Преобразования в группах методов не являются преобразованиями идентификаторов, ссылок или блоков;они являются преобразованиями групп методов.
Разве было бы невозможно включить сценарий 1 (не этот, конечно, конкретно, но в целом)?Я думаю, с точки зрения языка / компилятора, и будет ли это на самом деле полезным, или я просто (пытаюсь) безумно злоупотреблять здесь вещами?
Это не неосуществимо .У нас здесь довольно умная команда, и у нас нет теоретической причины, почему это невозможно сделать.Это просто не кажется нам функцией, которая добавляет языку больше ценности, чем стоимость дополнительной сложности.
Бывают моменты, когда это будет полезно.Например, я хотел бы быть в состоянии сделать это;Предположим, у меня есть static Func<A, R> Memoize<A, R>(this Func<A, R> f) {...}
:
var fib = (n=>n<2?1:fib(n-1)+fib(n-2)).Memoize();
Вместо того, что вы должны написать сегодня, а именно:
Func<int, int> fib = null;
fib = n=>n<2?1:fib(n-1)+fib(n-2);
fib = fib.Memoize();
Но, честно говоря, дополнительная сложность, которую предлагаемая функция добавляет кязык не оплачивается из-за небольшого преимущества в том, чтобы сделать приведенный выше код менее подробным.