Объем переменных в делегате

java.lang.NoSuchMethodError обычно происходит, если вы перепутали версии Scala. Например, это может быть вызвано различными зависимостями, которые были построены против Scala 2.11 и 2.12. Пожалуйста, проверьте, что все зависимости, а также кластер используют одну и ту же версию Scala.

8
задан Anders Rune Jensen 1 January 2009 в 12:57
поделиться

6 ответов

Это должен быть тот способ позволить анонимным методам (и лямбды) использовать локальные переменные и параметры, ограниченные по объему в содержании метода.

Обходные решения должны или использовать различные названия переменной или создать обычный метод.

9
ответ дан 5 December 2019 в 13:02
поделиться

"Закрытие", созданное анонимной функцией, несколько отличается от созданного на других динамических языках (я буду использовать JavaScript в качестве примера).

function thing() {
    var o1 = {n:1}
    var o2 = {dummy:"Hello"}
    return function() { return o1.n++; }
}

var fn = thing();
alert(fn());
alert(fn());

Этот небольшой блок JavaScript отобразится 1 затем 2. Анонимная функция может получить доступ к o1 переменной, потому что она существует на своей цепочке объема. Однако анонимная функция имеет совершенно независимый объем, в котором она могла создать другую o1 переменную и таким образом скрыть любого другого далее вниз цепочка объема. Обратите внимание также, что все переменные во всей цепочке остаются, следовательно o2 продолжил бы существовать, содержа ссылку на объект столько, сколько fn переменная содержит ссылку на функцию.

Теперь сравните с анонимными функциями C#:-

class C1 { public int n {get; set;} }
class C2 { public string dummy { get; set; } }

Func<int> thing() {
   var o1 = new C1() {n=1};
   var o2 = new C2() {dummy="Hello"};
   return delegate { return o1.n++; };
}
...
Func<int> fn = thing();
Console.WriteLine(fn());
Console.WriteLine(fn());

В этом случае анонимная функция не создает истинно независимый объем больше, чем объявление переменной ни в каком другом в функции {}, блок кода был бы (используемый в a foreach, if, и т.д.)

Следовательно те же правила применяются, код вне блока не может переменные доступа, объявленные в блоке, но Вы не можете снова использовать идентификатор также.

Закрытие создается, когда анонимная функция передается за пределами функции, в которой это было создано. Изменение от примера JavaScript состоит в том, что только те переменные, на самом деле используемые анонимной функцией, останутся, следовательно в этом случае, объект, сохраненный o2, будет доступен для GC, как только вещь завершается,

3
ответ дан 5 December 2019 в 13:02
поделиться

Это - потому что делегат может сослаться на переменные вне делегата:

int i = 1;
VoidFunction t = delegate { Console.WriteLine(i); };
0
ответ дан 5 December 2019 в 13:02
поделиться

На самом деле ошибка, кажется, не имеет никакого отношения к анонимным делегатам или lamda выражениям. При попытке скомпилировать следующую программу...

using System;

class Program
{
    static void Main()
    {
        // Action t = delegate
        {
            int i = 0;
        };

        int i = 1;
    }
}

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

0
ответ дан 5 December 2019 в 13:02
поделиться

Вы также получите CS0136 из кода как это:

  int i = 0;
  if (i == 0) {
    int i = 1;
  }

Объем 2-го объявления "i" однозначен, языки как C++ не имеют никакой говядины с ним. Но разработчики языка C# решили запретить его. Данный вышеупомянутый отрывок, Вы думаете, все еще думают, что это было плохой идеей? Добавьте набор дополнительного кода, и Вы могли уставиться на этот код некоторое время и не видеть ошибку.

Обходное решение является тривиальным и безболезненным, просто придумайте другое имя переменной.

1
ответ дан 5 December 2019 в 13:02
поделиться

Если я помню правильно, компилятор создает члена класса внешних переменных, на которые ссылаются в анонимном методе для создания этой работы.

Вот обходное решение:

class Program
    {
        void Main()
        {
            VoidFunction t = RealFunction;
            int i = 1;
        }
        delegate void VoidFunction();
        void RealFunction() { int i = 0; }
    } 
0
ответ дан 5 December 2019 в 13:02
поделиться
Другие вопросы по тегам:

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