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

时间:2009-12-17 04:02:16

标签: c# python

所以我只是在C#中学习一些新东西。蟒蛇。结果证明两种语言都支持嵌套方法(C#sort of do)。

的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 个答案:

答案 0 :(得分:16)

首先,意识到我无法给你一个完整的清单。如果你问“为什么螺丝刀有用?”,我会谈论螺丝和油漆罐盖,但会在白蚁检查中忽略它们的价值。当你问“为什么嵌套函数有用?”时,我可以告诉你有关范围,闭包和入口点的信息。

首先,嵌套可以替代类。我最近写了一些渲染代码,它采用专门的标记代码的文件名并返回一个位图。这自然会导致名为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”只是另一种说法。

所以,这里有两个地方嵌套类很有帮助。还有更多。这是一个工具。

答案 1 :(得分:8)

嵌套方法非常有用,因为在许多情况下,您希望传递行为,而不仅仅是数据。在许多情况下,除了更容易和更快速地编写之外,更清晰,更容易理解,只需在方法体中定义该行为,您将在其中使用它。

在.NET中,LINQ就是一个很好的例子。假设您要创建一个列表,其中每个值都是原始列表中值的两倍:

list.Select(i => i*2)

其中i => i*2相当于:

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

这比创建单独的函数更简单,更清晰。

此外,您声明的函数在其他地方可能没有意义(即,在您的方法范围之外)。在C#中,您甚至可以引用在方法体内声明的变量 - 使用非嵌套函数无法做到这一点。

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

答案 2 :(得分:4)

嵌套方法还允许您控制调用者的范围,并允许您访问内部创建的成员,而不会将它们暴露给类似范围内的其他函数(即类内)

答案 3 :(得分:4)

嵌套方法增加了代码的局部性,这是一件好事,因为您不必使用仅在一个地方使用的小型私有方法来污染类。

答案 4 :(得分:3)

尝试使用此Pythonish伪代码示例,了解此技术的一个用例:

def MyMethod(base):
    base = expensivePreparation(base)
    def MyInnerMethod(some_modifier):
        doSomethingCoolWith(base, some_modifier)

    return MyInnerMethod

process = MyMethod(some_obj)
process(arg1)
process(arg2)

答案 5 :(得分:1)

沿着上述几点,这些可以被视为高阶函数,这些函数本身可以获取或返回函数。

看看这个例子:

     static void Main(string[] args)
    {

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

        HigerOrderTest(NestedMethod)();
    }

     private static Action HigerOrderTest(Func<int, int> highFunction)
    {
          var sam = highFunction(3);

          Action DoIt =() =>
          {
              Console.WriteLine("Output is {0}.", sam);    
          };
             return DoIt;
    }

答案 6 :(得分:0)

这里已经有很多有用的答案了,但是这里有。

  • 内部阶级:不是!很好的尝试,但太多的工作。嵌套函数/触发器更快更快。 King Java的[1]类有一个方法[2]真的很糟糕,嵌套函数(或程序)绕过这样的句法废话。
  • 功能分解:将较长的例程分解为较小的例程,这些例程对于未使用它们的其他地方是隐藏的。帕斯卡尔支持这一点,我很确定它即使在那时(70年代初期)也不是一项新发明。
  • 闭包:在别处提到,但很有用。在封闭函数中使用局部变量来初始化生成的函数,并返回自定义函数(或以其他方式使用生成的代码)

1:http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html“King Java”

2:http://en.wikipedia.org/wiki/Function_object#In_Java“功能对象/仿函数”

答案 7 :(得分:0)

您可能已经意识到将函数传递给其他函数的用处,例如,提供具有比较函数的sort()例程,以及map()filter()的明显示例等等。同样,作为另一个函数的结果接收函数通常很有用。最常见的用法是closures,但currying也很常见。

闭包的核心好处是能够在运行时创建一个新函数,该函数包含在该时间点执行所需的所有时间信息。在不支持闭包的语言实现中,这种状态管理通常通过类完成,可以说不太优雅:设置对象实例变量,然后在需要时读取。闭包提供了一种将状态捆绑在一起的方法。

因此,作为理解的基本点,将嵌套函数视为一种编写现场函数以执行特定操作的方法可能会有所帮助,其中这些操作的详细信息将在运行时被识别,但您只能我希望稍后再执行该行动。

嵌套函数还可以做其他事情,但你必须从某个地方开始。