局部函数vs Lambda C#7.0

局部函数vs Lambda C#7.0,c#,function,lambda,c#-7.0,C#,Function,Lambda,C# 7.0,我正在查看中的新实现,我发现它们实现了本地函数很有趣,但我无法想象一个场景,其中本地函数比lambda表达式更受欢迎,这两者之间的区别是什么 我确实理解lambda是匿名的,而本地函数不是,但我无法理解一个真实的场景,其中本地函数比lambda表达式有优势 任何例子都将不胜感激。谢谢。: 您需要一个助手函数。您只能在单个函数中使用它,并且它可能使用包含该函数的范围内的变量和类型参数。另一方面,与lambda不同,您不需要将其作为第一类对象,因此不需要为其指定委托类型并分配实际的委托对象。此外,您

我正在查看中的新实现,我发现它们实现了本地函数很有趣,但我无法想象一个场景,其中本地函数比lambda表达式更受欢迎,这两者之间的区别是什么

我确实理解lambda是匿名的,而本地函数不是,但我无法理解一个真实的场景,其中本地函数比lambda表达式有优势

任何例子都将不胜感激。谢谢。

您需要一个助手函数。您只能在单个函数中使用它,并且它可能使用包含该函数的范围内的变量和类型参数。另一方面,与lambda不同,您不需要将其作为第一类对象,因此不需要为其指定委托类型并分配实际的委托对象。此外,您可能希望它是递归的或泛型的,或者将其实现为迭代器

要进一步扩展,其优点是:

  • 表演

    创建lambda时,必须创建一个委托,在这种情况下,这是不必要的分配。本地函数实际上只是函数,不需要委托

    此外,局部函数在捕获局部变量方面更有效:lambda通常将变量捕获到类中,而局部函数可以使用struct(使用
    ref
    传递),这同样避免了分配

    这也意味着调用本地函数更便宜,而且它们可以内联,可能会进一步提高性能

  • 局部函数可以是递归的

    lambda也可以是递归的,但它需要笨拙的代码,首先将
    null
    赋值给委托变量,然后是lambda。局部函数自然可以是递归的(包括相互递归的)

  • 局部函数可以是泛型的

    lambda不能是泛型的,因为它们必须被分配给具有具体类型的变量(该类型可以使用外部范围中的泛型变量,但这不是同一件事)

  • 局部函数可以作为迭代器实现

    Lambdas不能使用
    收益返回
    (和
    收益中断
    )关键字来实现
    IEnumerable
    -返回功能。可以使用本地功能

  • 本地功能看起来更好

    这在上面的引用中没有提到,可能只是我个人的偏见,但我认为普通函数语法看起来比将lambda赋值给委托变量要好。局部函数也更简洁

    比较:

    int add(int x, int y) => x + y;
    Func<int, int, int> add = (x, y) => x + y;
    
    intadd(intx,inty)=>x+y;
    Func add=(x,y)=>x+y;
    
  • 除此之外,本地功能还有一个优势:
    它们可以在函数中的任何位置定义,即使在
    return
    语句之后也是如此

    public double DoMath(double a, double b)
    {
        var resultA = f(a);
        var resultB = f(b);
        return resultA + resultB;
    
        double f(double x) => 5 * x + 3;
    }
    

    我使用内联函数来避免垃圾收集压力,特别是在处理长时间运行的方法时。假设一个人想要获得给定股票代码的两年或市场数据。此外,如果需要,可以打包许多功能和业务逻辑

    我们要做的是打开一个到服务器的套接字连接,并在将事件绑定到事件的数据上循环。我们可以用设计类的同样方式来考虑它,只有一种方法不是到处编写帮助器方法,它们实际上只为一部分功能工作。下面是一些可能的示例,请注意,我使用的是变量,“helper”方法位于finally下面。在最后一个示例中,我很好地删除了事件处理程序,如果我的Exchange类是外部的/注入的,我就不会注册任何挂起的事件处理程序

    void List<HistoricalData> RequestData(Ticker ticker, TimeSpan timeout)
    {
        var socket= new Exchange(ticker);
        bool done=false;
        socket.OnData += _onData;
        socket.OnDone += _onDone;
        var request= NextRequestNr();
        var result = new List<HistoricalData>();
        var start= DateTime.Now;
        socket.RequestHistoricalData(requestId:request:days:1);
        try
        {
          while(!done)
          {   //stop when take to long….
            if((DateTime.Now-start)>timeout)
               break;
          }
          return result;
    
        }finally
        {
            socket.OnData-=_onData;
            socket.OnDone-= _onDone;
        }
    
    
       void _OnData(object sender, HistoricalData data)
       {
           _result.Add(data);
       }
       void _onDone(object sender, EndEventArgs args)
       {
          if(args.ReqId==request )
             done=true;
       } 
    }
    
    void List RequestData(Ticker-Ticker,TimeSpan超时)
    {
    var套接字=新交易所(股票代码);
    bool done=false;
    socket.OnData+=\u OnData;
    socket.OnDone+=\u OnDone;
    var request=NextRequestNr();
    var result=新列表();
    var start=DateTime.Now;
    socket.RequestHistoricalData(requestId:request:days:1);
    尝试
    {
    而(!完成)
    {//需要很长时间时停止…。
    if((DateTime.Now start)>超时)
    打破
    }
    返回结果;
    }最后
    {
    socket.OnData-=\u OnData;
    socket.OnDone-=\u OnDone;
    }
    void_OnData(对象发送方,历史数据)
    {
    _结果.添加(数据);
    }
    void _onDone(对象发送方、EndEventArgs参数)
    {
    if(args.ReqId==请求)
    完成=正确;
    } 
    }
    

    您可以看到下面提到的优点,这里您可以看到一个示例实现。希望这有助于解释其好处

    如果您还想知道如何测试本地功能,您应该检查一下,因为它具有测试本地功能。下面是一个将要测试的简单类示例:

    public class Foo // the class under test
    { 
        public int GetResult() 
        { 
            return 100 + GetLocal(); 
            int GetLocal () 
            { 
                return 42; 
            } 
        } 
    }
    
    下面是测试结果:

    [TestClass] 
    public class MockLocalFunctions 
    { 
        [TestMethod] 
        public void BasicUsage() 
        { 
            //Arrange 
            var foo = Mock.Create<Foo>(Behavior.CallOriginal); 
            Mock.Local.Function.Arrange<int>(foo, "GetResult", "GetLocal").DoNothing(); 
    
            //Act 
            var result = foo. GetResult(); 
    
            //Assert 
            Assert.AreEqual(100, result); 
        } 
    } 
    
    [TestClass]
    公共类MockLocalFunctions
    { 
    [测试方法]
    公共空间基本概念()
    { 
    //安排
    var foo=Mock.Create(Behavior.CallOriginal);
    Mock.Local.Function.Arrange(foo,“GetResult”,“GetLocal”).DoNothing();
    //表演
    var result=foo.GetResult();
    //断言
    断言.AreEqual(100,结果);
    } 
    } 
    
    这里有一个到JustMock的链接


    免责声明。我是负责.

    泛型、out参数、递归函数(无需将lambda初始化为null)等的开发人员之一。@KirkWoll-您应该将此作为答案发布。我想补充一点,本地函数在调用方有参数名。Lambdas没有。@Lensflare Lambdas的参数名确实没有保留,但这是因为它们必须转换为委托,委托有自己的名称。例如:
    Func f=(x,y)=>x+y;f(arg1:1,arg2:1)。很棒的列表!但是,我可以想象IL/JIT编译器如何执行1中提到的所有优化。如果