为什么局部函数不总是隐藏在C#7中? [英] Why is a local function not always hidden in C#7?

查看:235
本文介绍了为什么局部函数不总是隐藏在C#7中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在下面显示的是一个理论问题.但是我对新的C#7编译器如何工作以及如何解析本地函数感兴趣.

What I am showing below, is rather a theoretical question. But I am interested in how the new C#7 compiler works and resolves local functions.

C#7 中,我可以使用本地函数.例如(您可以在

In C#7 I can use local functions. For example (you can try these examples in LinqPad beta):

示例1:嵌套的Main()

void Main()
{
    void Main()
    {
        Console.WriteLine("Hello!");
    }
    Main();
}

示例1的DotNetFiddle

不是以递归方式调用Main(),而是一次调用了本地函数Main(),因此其输出为:

Rather than calling Main() in a recursive way, the local function Main() is being called once, so the output of this is:

你好!

编译器接受此警告而没有警告和错误.

The compiler accepts this without warnings and errors.

示例2: 在这里,我要更深入一点,例如:

Example 2: Here, I am going one level deeper, like:

示例2的DotNetFiddle

在这种情况下,我也会期望得到相同的输出,因为调用了最里面的本地函数,然后向上一级,Main()只是具有本地范围的另一个本地函数,因此它与第一个例子.

In this case, I would also expect the same output, because the innermost local function is called, then one level up, Main() is just another local function with a local scope, so it should be not much different from the first example.

但是,令我惊讶的是,我遇到了一个错误:

But here, to my surprise, I am getting an error:

CS0136无法在此范围内声明名为"Main"的本地或参数,因为该名称在封闭的本地范围内用于定义本地或参数

CS0136 A local or parameter named 'Main' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter


问题: 您能否解释为什么在示例2中会发生此错误,而在示例1中是不是?


Question: Can you explain why this error happens in Example 2, but not in Example 1?

我认为,每个内部Main()都将具有局部作用域,并且被隐藏在外部.

I thought, each inner Main() would have a local scope and is hidden outside.

更新: 感谢所有到目前为止做出过对接的人(答案或评论),您为理解C#编译器的行为所写的内容非常值得.

Update: Thank you to all who have made contibutions so far (either answers or comments), it is very worthwile what you wrote to understand the behavior of the C# compiler.

根据我的阅读并在考虑了可能性之后,我在您的帮助下发现,它可能是编译器错误,也可能是设计错误.

From what I read, and after considering the possibilities, what I found out with your help is that it can be either a compiler bug or behavior by design.

回想一下C#的一些设计目标,使其有别于C ++之类的语言.

Recall that C# had some design goals which differentiate it from languages like C++.

如果您有兴趣进行进一步调查,请执行以下操作: 我已将最里面的函数重命名为MainL:

If you're interested what I have done to investigate it further: I have renamed the innermost function to MainL like:

示例2b:

void Main()
{
    void Main()
    {
        void MainL()
        {
            Console.WriteLine("Hello!");
        }
        MainL();
    }
    Main();     
}

此修改后的示例可以编译并成功运行.

This modified example compiles and runs successfully.

现在,当您使用 LinqPad 进行编译时,然后切换到 IL 标签中,您可以看到编译器做了什么:

Now when you compile this with LinqPad and then switch to the IL tab you can see what the compiler did:

它创建了最里面的MainL函数作为g__MainL0_1,封闭的Main函数具有标签g__Main0_0.

It created the innermost MainL function as g__MainL0_1, the enclosing Main function has the label g__Main0_0.

这意味着,如果从MainL中删除L,您会注意到编译器已经以一种独特的方式对其进行了重命名,因为这样的代码如下:

That means, if you remove the L from MainL you will notice that the compiler already renames it in a unique way, because then the code looks like:

IL_0000:  call        UserQuery.<Main>g__Main0_0
IL_0005:  ret         

<Main>g__Main0_0:
IL_0000:  call        UserQuery.<Main>g__Main0_1
IL_0005:  ret         

<Main>g__Main0_1:
IL_0000:  ldstr       "Hello!"
IL_0005:  call        System.Console.WriteLine
IL_000A:  ret         

仍然可以正确解决.由于示例2中的代码看起来不像这样,因为编译器因错误而停止,所以我现在假定行为是设计使然,不太可能是编译器错误.

which would still resolve correctly. Since the code doesn't look like this in Example 2, because the compiler stops with an error, I do now assume that the behavior is by design, it is not likely a compiler bug.

结论: 你们中的有些人写道,在C ++中,对局部函数的递归解析可能导致重构问题,而另一些人写道,C#中的这种行为是编译器对局部变量所做的操作(请注意,错误消息是相同的)-甚至所有这些确认我认为这是设计使然,并且没有错误.

Conclusion: Some of you wrote that in C++ recursive resolution of local functions can lead to refactoring issues, and others wrote that this kind of behavior in C# is what the compiler does with local variables (note that the error message is the same) - all that even confirms me thinking it was done like this by design and is no bug.

推荐答案

由于Stackoverflow不允许多个答案,因此我认为这是最公平的方法.我将此答案创建为社区Wiki(因此我不会获得该答案的任何代表点),投票赞成以下两个答案,并将它们添加为链接以供您参考(因此,他们很荣幸能分别获得他们的答案的代表点):

Since Stackoverflow does not allow multiple answers, I thought what would be the fairest way. I created this answer as community wiki (so I won't get any rep points for this answer), upvoted the two answers below and added them as link for your reference (so they are honored and get rep points for their answers individually):

  • Answer 1: v-andrew
  • Answer 2: Jon Hanna

我在问题中创建了一个摘要,其中包含我从评论和答案中获得的所有信息:

And I created a summary in the question containing all information I got from you from the comments and from the answers:

这篇关于为什么局部函数不总是隐藏在C#7中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆