您当前的位置: 首页 >  c#

Phil Arist

暂无认证

  • 7浏览

    0关注

    276博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

C# 本地函数与 Lambda 表达式

Phil Arist 发布时间:2021-09-01 09:18:57 ,浏览量:7

C# 局部函数通常被视为 lambda 表达式的进一步增强。虽然功能是相关的,但也存在重大差异。

Local Functions 是嵌套函数[1]功能的 C# 实现。一种语言在支持 lambdas 之后获得对嵌套函数的支持几个版本是有点不寻常的。通常情况相反。

Lambda 或一般的一流函数需要实现未在堆栈上分配且生命周期与需要它们的功能对象相关联的局部变量。如果不依赖垃圾收集或通过捕获列表等解决方案将变量所有权的负担减轻给用户,则几乎不可能正确有效地实现它们。对于某些早期语言来说,这是一个严重的阻塞问题。嵌套函数的简单实现不会遇到这种复杂情况,因此一种语言更常见的是仅支持嵌套函数而不支持 lambda。

无论如何,由于 C# 长期以来一直使用 lambda,因此从差异和相似之处来看本地函数确实是有意义的。

Lambda 表达式

Lambda 表达式x => x + x是抽象地表示一段代码以及它如何绑定到其词法环境中的参数和变量的表达式。作为代码的抽象表示,lambda 表达式不能单独使用。为了使用由 lambda 表达式生成的值,需要将其转换为更多内容,例如委托或表达式树。

using System;
using System.Linq.Expressions;

class Program
{
    static void Main(string[] args)
    {
        // can't do much with the lambda expression directly
        // (x => x + x).ToString();  // error

        // can assign to a variable of delegate type and invoke
        Func f = (x => x + x);
        System.Console.WriteLine(f(21)); // prints "42"

        // can assign to a variable of expression type and introspect
        Expression e = (x => x + x);
        System.Console.WriteLine(e);     // prints "x => (x + x)"
    }
}

有几点值得注意:

•lambdas 是产生函数值的表达式。•lambda 值的生命周期是无限的——从 lambda 表达式的执行开始,只要存在对该值的任何引用。这意味着 lambda 从封闭方法中使用或“捕获”的任何局部变量都必须在堆上分配。由于 lambda 值的生命周期不受产生它的堆栈帧的生命周期的限制,因此不能在该堆栈帧上分配变量。•lambda 表达式要求在执行 lambda 表达式时明确分配主体中使用的所有外部变量。lambda 的第一次和最后一次使用的时刻很少是确定性的,因此该语言假设 lambda 值可以在创建后立即使用,只要它们是可访问的。因此,一个 lambda 值在创建时必须是完全可用的,并且它使用的所有外部变量都必须明确分配。

  int x;

        // ERROR: 'x' is not definitely assigned
        Func f = () => x;

•lambdas 没有名字,也不能被象征性地引用。特别是 lambda 表达式不能递归声明。

注意:可以通过调用分配给 lambda 的变量或传递给自应用其参数的高阶方法来创建递归 lambda(请参阅:C# 中的匿名递归[2]),但这不会表达真正的自我参照。

本地函数

局部函数基本上只是在另一个方法中声明的方法,作为一种降低方法对其声明范围内的可见性的方法。

自然地,局部函数中的代码可以访问其包含范围内可访问的所有内容——局部变量、封闭方法的参数、类型参数、局部函数。一个值得注意的例外是外部方法标签的可见性。封闭方法的标签在局部函数中不可见。这只是普通的词法范围,它的工作原理与 lambdas 相同。

public class C
{
    object o;

    public void M1(int p)
    {
        int l = 123;

        // lambda has access to o, p, l,
        Action a = ()=> o = (p + l);
    }

    public void M2(int p)
    {
        int l = 123;

        // Local Function has access to o, p, l,
        void a()
        {
          o = (p + l);
        }
    }
}

与 lambda 的明显区别在于局部函数具有名称并且可以在没有任何间接方式的情况下使用。局部函数可以是递归的。

static int Fac(int arg)
{
    int FacRecursive(int a)
    {
        return a             
关注
打赏
1662360869
查看更多评论
0.1852s