문제

나는 다음과 같은 이상한 것을 발견했다. 그런 다음 다시, 동일한 "버그"에 의심 할 수없는 동적 언어로 폐쇄를 사용했습니다. 다음은 컴파일러를 불행하게 만듭니다.

VoidFunction t = delegate { int i = 0; };

int i = 1;

그것은 말한다 :

'I'라는 로컬 변수는이 범위에서 선언 될 수 없습니다. 'I'와는 다른 의미를 부여하기 때문에 이미 '자식'범위에 사용되어 다른 것을 나타냅니다.

따라서 이것은 기본적으로 대의원 내부에서 선언 된 변수가 선언 된 함수의 범위를 갖게 될 것임을 의미합니다. 정확히 내가 기대했던 것이 아닙니다. 나는 그 기능을 부르려고하지 않았다. 최소한 일반적인 LISP에는 변수가 동적 이름을 가져야한다고 말하는 기능이 있습니다. 이것은 누출되지 않은 매크로를 만들 때 특히 중요하지만, 그와 같은 것이 여기서도 도움이 될 것입니다.

그래서 다른 사람들 이이 문제를 해결하기 위해 무엇을하는지 궁금합니다.

명확히하기 위해, 내가 선언 한 변수가 선언 된 변수를 방해하지 않는 솔루션을 찾고 있습니다. ~ 후에 대표. 그리고 나는 여전히 대의원 전에 선언 된 변수를 캡처 할 수 있기를 원합니다.

도움이 되었습니까?

해결책

It has to be that way to allow anonymous methods (and lambdas) to use local variables and parameters scoped in the containing method.

The workarounds are to either use different names for the variable, or create an ordinary method.

다른 팁

The "closure" created by an anonymous function is somewhat different from that created in other dynamic languages (I'll use Javascript as an example).

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

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

This little chunk of javascript will display 1 then 2. The anonymous function can access the o1 variable because it exists on its scope chain. However the anonymous function has an entirely independant scope in which it could create another o1 variable and thereby hide any other further down the scope chain. Note also that all variables in the entire chain remain, hence o2 would continue to exist holding an object reference for as long as the fn varialbe holds the function reference.

Now compare with C# anonymous functions:-

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());

In this case the anonymous function is not creating a truely independant scope any more than variable declaration in any other in-function { } block of code would be (used in a foreach, if, etc.)

Hence the same rules apply, code outside the block cannot access variables declared inside the block but you cannot reuse an identifier either.

A closure is created when the anonymous function is passed outside of the function that it was created in. The variation from the Javascript example is that only those variables actually used by the anonymous function will remain, hence in this case the object held by o2 will be available for GC as soon as thing completes,

You'll also get CS0136 from code like this:

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

The scope of the 2nd declaration of "i" is unambiguous, languages like C++ don't have any beef with it. But the C# language designers decided to forbid it. Given the above snippet, do you think still think that was a bad idea? Throw in a bunch of extra code and you could stare at this code for a while and not see the bug.

The workaround is trivial and painless, just come up with a different variable name.

It's because the delegate can reference variables outside the delegate:

int i = 1;
VoidFunction t = delegate { Console.WriteLine(i); };

If I remember correctly, the compiler creates a class member of the outside variables referenced in the anonymous method, in order to make this work.

Here is a workaround:

class Program
    {
        void Main()
        {
            VoidFunction t = RealFunction;
            int i = 1;
        }
        delegate void VoidFunction();
        void RealFunction() { int i = 0; }
    } 

Actually, the error doesn't seem to have anything to do with anonymous delegates or lamda expressions. If you try to compile the following program ...

using System;

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

        int i = 1;
    }
}

... you get exactly the same error, no matter whether you comment in the line or not. The error help shows a very similar case. I think it is reasonable to disallow both cases on the grounds that programmers could confuse the two variables.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top