委托中变量的范围

发布于 2024-07-11 06:08:34 字数 556 浏览 4 评论 0原文

我发现以下内容相当奇怪。 话又说回来,我主要在动态语言中使用闭包,这不应该被怀疑为相同的“错误”。 以下内容让编译器不高兴:

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

int i = 1;

它说:

名为“i”的局部变量不能 在此范围内声明,因为它 会给“i”赋予不同的含义, 已经在“孩子”中使用过 表示其他事物的范围

所以这基本上意味着在委托内声明的变量将具有其中声明的函数的范围。这并不完全是我所期望的。 我什至没有尝试调用该函数。 至少 Common Lisp 有一个特性,如果你真的希望变量是本地的,那么你可以说变量应该有一个动态名称。 这在创建不会泄漏的宏时尤其重要,但类似的东西在这里也很有帮助。

所以我想知道其他人做了什么来解决这个问题?

为了澄清这一点,我正在寻找一种解决方案,其中我在委托中声明的变量不会干扰委托之后声明的变量。 我希望仍然能够捕获委托之前声明的变量。

I found the following rather strange. Then again, I have mostly used closures in dynamic languages which shouldn't be suspectable to the same "bug". The following makes the compiler unhappy:

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

int i = 1;

It says:

A local variable named 'i' cannot be
declared in this scope because it
would give a different meaning to 'i',
which is already used in a 'child'
scope to denote something else

So this basically means that variables declared inside a delegate will have the scope of the function declared in. Not exactly what I would have expected. I havn't even tried to call the function. At least Common Lisp has a feature where you say that a variable should have a dynamic name, if you really want it to be local. This is particularly important when creating macros that do not leak, but something like that would be helpful here as well.

So I'm wondering what other people do to work around this issue?

To clarify I'm looking for a solution where the variables I declare in the delegete doesn't interfere with variables declared after the delegate. And I want to still be able to capture variables declared before the delegate.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

顾挽 2024-07-18 06:08:34

必须采用这种方式才能允许匿名方法(和 lambda)使用包含方法范围内的局部变量和参数。

解决方法是为变量使用不同的名称,或者创建普通方法。

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.

罪#恶を代价 2024-07-18 06:08:34

匿名函数创建的“闭包”与其他动态语言创建的“闭包”有些不同(我将使用 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 变量,从而隐藏作用域链中的任何其他变量。 还要注意,整个链中的所有变量都会保留,因此只要 fn 变量保存函数引用,o2 就会继续存在并保存对象引用。

现在与 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());

在这种情况下,匿名函数不会创建真正独立的作用域,就像任何其他函数内 { } 代码块中的变量声明一样(在 foreachif 等)

因此,应用相同的规则,块外部的代码无法访问块内部声明的变量,但也不能重用标识符。

当匿名函数被传递到创建它的函数之外时,就会创建一个闭包。与 Javascript 示例的不同之处在于,只有匿名函数实际使用的那些变量才会保留,因此在这种情况下,o2 持有的对象将事情完成后即可用于 GC,

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,

放飞的风筝 2024-07-18 06:08:34

您还可以从这样的代码中得到 CS0136:

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

“i”的第二个声明的范围是明确的,像 C++ 这样的语言对此没有任何影响。 但 C# 语言设计者决定禁止它。 鉴于上面的片段,您是否仍然认为这是一个坏主意? 添加一堆额外的代码,您可能会盯着这段代码一段时间而看不到错误。

解决方法既简单又轻松,只需想出一个不同的变量名称即可。

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.

一片旧的回忆 2024-07-18 06:08:34

这是因为委托可以引用委托外部的变量:

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

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

int i = 1;
VoidFunction t = delegate { Console.WriteLine(i); };
無處可尋 2024-07-18 06:08:34

如果我没记错的话,编译器会创建匿名方法中引用的外部变量的类成员,以便完成这项工作。

这是一个解决方法:

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

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; }
    } 
因为看清所以看轻 2024-07-18 06:08:34

实际上,该错误似乎与匿名委托或 lamda 表达式没有任何关系。 如果您尝试编译以下程序……

using System;

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

        int i = 1;
    }
}

您会得到完全相同的错误,无论您是否在该行中进行注释。 错误帮助显示了非常相似的情况。 我认为不允许这两种情况是合理的,因为程序员可能会混淆这两个变量。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文