C# 3.0 универсальный вывод типа - передача делегата как параметр функции

Примечание: Неинициализированное смещение строки: *

Как видно из названия, возникает такой тип ошибки, когда вы, скорее всего, пытаетесь перебрать или найти значение из массива с не- существующий ключ.

Считаем, что вы пытаетесь показать каждую букву из $string

$string = 'ABCD'; 
for ($i=0, $len = strlen($string); $i <= $len; $i++){
    echo "$string[$i] \n"; 
}

. Вышеприведенный пример сгенерирует ( онлайн-демонстрацию ):

A
B
C
D
Notice: Uninitialized string offset: 4 in XXX on line X

И, как только скрипт заканчивается эхом D, вы получите ошибку, потому что внутри цикла for() вы сказали PHP, чтобы показать вам от первого до пятого символа строки из 'ABCD' Что, существует, но поскольку цикл начинает отсчитываться от 0 и эха D к моменту достижения значения 4, он выдает ошибку смещения.

Аналогичные ошибки:

23
задан abatishchev 4 July 2011 в 17:37
поделиться

4 ответа

Возможно, это сделает его более ясным:

public class SomeClass
{
    static void foo(int x) { }
    static void foo(string s) { }
    static void bar<T>(Action<T> f){}
    static void barz(Action<int> f) { }
    static void test()
    {
        Action<int> f = foo;
        bar(f);
        barz(foo);
        bar(foo);
        //these help the compiler to know which types to use
        bar<int>(foo);
        bar( (int i) => foo(i));
    }
}

нечто не является действием - нечто является группой метода.

  • В операторе присваивания, компилятор может сказать ясно, о каком нечто Вы говорите, так как международный тип определяется.
  • В barz (нечто) оператор, компилятор может сказать, о каком нечто Вы говорите, так как международный тип определяется.
  • В панели (нечто) оператор, это могло быть любое нечто с единственным параметром - таким образом, компилятор сдается.

Редактирование: я добавил еще два способа помочь компилятору выяснить тип (т.е. - как пропустить шаги вывода).

От моего чтения статьи в ответе JSKEET, решение не вывести тип, кажется, основано на взаимном выводящем сценарии, такой как

  static void foo<T>(T x) { }
  static void bar<T>(Action<T> f) { }
  static void test()
  {
    bar(foo); //wut's T?
  }

, Так как общая проблема была, не решают - способный, они выбирают к левым определенным проблемам, где решение существует как нерешенное.

В результате этого решения, Вы не будете добавлять перегрузку для метода и получать много беспорядка типа от всех вызывающих сторон, которые привыкли к единственной членской группе метода. Я предполагаю, что это - хорошая вещь.

17
ответ дан Amy B 29 November 2019 в 02:25
поделиться

Обоснование состоит в том, что, если тип когда-нибудь расширяется, не должно быть никакой возможности отказа. т.е. если нечто метода (строка) добавляется к типу, это никогда не должно иметь значения для существующего кода - пока содержание существующих методов не изменяется.

По этой причине, даже когда существует только одно нечто метода, ссылка на нечто (известный как группа метода) не может быть брошена делегату non-type-specific, такой как Action<T>, но только определенному для типа делегату такой как Action<int>.

7
ответ дан configurator 29 November 2019 в 02:25
поделиться

Это немного нечетно, да. Спецификацию C# 3.0 для вывода типа трудно считать и имеет ошибки в нем, но это взгляды как он должно работать. В первой фазе (разделяют 7.4.2.1) я полагаю, что существует ошибка - это не должно упоминать группы метода в первом маркере (поскольку они не покрыты явным выводом типа параметра (7.4.2.7) - что означает, что это должно использовать выходной вывод типа (7.4.2.6). То, что взгляды как он должны работать - но очевидно это не делает: (

я знаю, что MS надеется улучшать спецификацию для вывода типа, таким образом, это могло бы стать немного более ясным. Я также знаю, что независимо от трудности чтения его, существуют ограничения на группы метода и вывод типа - ограничения, которые могли быть специальными в корпусе, когда группа метода является только на самом деле отдельным методом по общему признанию.

у Eric Lippert есть запись в блоге на вывод типа возврата, не работающий с группами метода , который является подобен к этому случаю - но здесь мы не интересуемся типом возврата, только на типе параметра. Возможно, что другие сообщения в его серии вывода типа могут помочь все же.

5
ответ дан Jon Skeet 29 November 2019 в 02:25
поделиться

Имейте в виду, что задание

Action<int> f = foo;

уже содержит много синтаксического сахара. На самом деле компилятор генерирует код для этого оператора:

Action<int> f = new Action<int>(foo);

Соответствующий вызов метода компилируется без проблем:

bar(new Action<int>(foo));

Fwiw, поэтому помогает компилятору вывести аргумент типа:

bar<int>(foo);

Таким образом, все сводится к вопросу, почему сахар в операторе присваивания, а не в вызове метода? Я должен был бы предположить, что это потому, что сахар однозначен в задании, есть только одна возможная замена. Но в случае вызовов методов авторам компилятора уже приходилось сталкиваться с проблемой разрешения перегрузки. Правила которых довольно сложны. Они, вероятно, просто не удосужились.

5
ответ дан Hans Passant 29 November 2019 в 02:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: