嵌套方法?它们有什么用?

13 投票
8 回答
8978 浏览
提问于 2025-04-15 17:07

我最近在学习一些新的东西,主要是C#和Python。结果发现这两种语言都支持嵌套方法(C#有点支持)。

Python:

def MyMethod():

    print 'Hello from a method.'

    def MyInnerMethod():
        print 'Hello from a nested method.'

    MyInnerMethod()

C#(使用.NET 3.5中的新特性):*

static void Main()
{
    Console.WriteLine("Hello from main.");

    Func<int, int> NestedMethod =
        (x) =>
        {
            Console.WriteLine("In nested method. Value of x is {0}.", x);
            return x;
        };

    int result = NestedMethod(3);
}

那么,为什么嵌套方法这么重要呢?它们有什么用处呢?


**这段C#代码还没有经过测试。如果编译不通过,可以随意修改。*

8 个回答

5

嵌套方法让你可以控制调用者的范围,同时也能让你访问内部创建的成员,而这些成员不会被同一范围内的其他函数看到(比如在一个类里面)。

7

嵌套方法很有用,因为有很多情况下你想传递的是行为,而不仅仅是数据。在很多情况下,把行为直接写在你要用的方法里,这样更清晰、更容易理解,而且写起来也更简单、更快。

在.NET中,LINQ就是一个很好的例子。假设你想创建一个列表,每个值都是原列表中对应值的两倍:

list.Select(i => i*2)

这里的i => i*2相当于:

Func<int,int> double = delegate(int x) { return x*2; }

这样做简单多了,也更清楚,而不是单独创建一个函数。

而且,你在方法里声明的函数可能在其他地方(也就是方法外面)没有意义。在C#中,你甚至可以引用在方法体内声明的变量,而这在非嵌套函数中是做不到的。

当然,你也可以滥用嵌套函数……

17

首先,要明白我不能给你一个完整的列表。如果你问“螺丝刀有什么用?”,我可能会说它可以用来拧螺丝和打开油漆罐的盖子,但我可能会忽略它在白蚁检查中的价值。当你问“嵌套函数有什么用?”时,我可以告诉你关于作用域、闭包和入口点的事情。

首先,嵌套函数可以作为类的替代方案。我最近写了一些渲染代码,它接收一个文件名,里面是特定的标记代码,然后返回一个位图。这自然就需要一些函数,比如 grab_markup_from_filename() 和 render_text_onto_image() 等等。最简洁的组织方式是有一个入口点,叫做 generate_png_from_markup_filename()。这个入口点完成了它的工作,使用嵌套函数来实现任务。因为没有需要保存状态的对象,所以不需要类。我的另一个选择是创建一个模块,里面有私有方法来隐藏我的辅助函数,但那样会显得更乱。

def generate_png_from_markup_filename(filename):
    def grab_markup_from_filename():
        ... 
    ... # code that calls grab_markup_from_filename() to make the image
    return image

其次,我使用嵌套函数来实现闭包。最常见的例子是创建装饰器。诀窍在于我返回一个内部函数的引用,这样内部函数和外部参数的值就不会被垃圾回收。

def verify_admin(function_to_call):
    def call_on_verify_admin(*args, **kwargs):
        if is_admin(global.session.user):
            return function_to_call(*args, **kwargs)
        else:
           throw Exception("Not Admin")
    return call_on_verify_admin  # the return value of verify_admin()

这样使用:

 def update_price(item, price):
     database.lookup(item).set_field('price', price)
 update_price = verify_admin(update_price)

或者,更简洁地:

 @verify_admin
 def update_price(item, price):
     database.lookup(item).set_field('price', price)

没错,这确实很难追踪。记住,“def”只是另一种语句。

所以,这里有两个地方嵌套类是有用的。还有更多的用途。这只是一个工具。

撰写回答