我正在看c# 7.0的新实现,我发现有趣的是,他们实现了局部函数,但我无法想象一个场景,局部函数将优先于lambda表达式,两者之间的区别是什么。
我知道lambda是匿名函数,而局部函数不是,但我不知道在现实世界中,局部函数比lambda表达式有什么优势
任何例子都将非常感激。谢谢。
我正在看c# 7.0的新实现,我发现有趣的是,他们实现了局部函数,但我无法想象一个场景,局部函数将优先于lambda表达式,两者之间的区别是什么。
我知道lambda是匿名函数,而局部函数不是,但我不知道在现实世界中,局部函数比lambda表达式有什么优势
任何例子都将非常感激。谢谢。
当前回答
除了svick的回答之外,局部函数还有一个优点: 它们可以定义在函数中的任何位置,甚至在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;
}
其他回答
除了svick的回答之外,局部函数还有一个优点: 它们可以定义在函数中的任何位置,甚至在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;
}
Mads Torgersen在c#设计会议笔记中解释了这一点,其中第一次讨论了局部函数:
你需要一个辅助函数。您只能从单个函数中使用它,并且它可能使用包含该函数的作用域内的变量和类型参数。另一方面,不像lambda你不需要它作为第一类对象,所以你不需要给它一个委托类型和分配一个实际的委托对象。此外,您可能希望它是递归的或泛型的,或者将它实现为迭代器。
更详细地说,它的优点是:
Performance. When creating a lambda, a delegate has to be created, which is an unnecessary allocation in this case. Local functions are really just functions, no delegates are necessary. Also, local functions are more efficient with capturing local variables: lambdas usually capture variables into a class, while local functions can use a struct (passed using ref), which again avoids an allocation. This also means calling local functions is cheaper and they can be inlined, possibly increasing performance even further. Local functions can be recursive. Lambdas can be recursive too, but it requires awkward code, where you first assign null to a delegate variable and then the lambda. Local functions can naturally be recursive (including mutually recursive). Local functions can be generic. Lambdas cannot be generic, since they have to be assigned to a variable with a concrete type (that type can use generic variables from the outer scope, but that's not the same thing). Local functions can be implemented as an iterator. Lambdas cannot use the yield return (and yield break) keyword to implement IEnumerable<T>-returning function. Local functions can. Local functions look better. This is not mentioned in the above quote and might be just my personal bias, but I think that normal function syntax looks better than assigning a lambda to a delegate variable. Local functions are also more succinct. Compare: int add(int x, int y) => x + y; Func<int, int, int> add = (x, y) => x + y;
如果你也想知道如何测试本地函数,你应该检查JustMock,因为它有功能来做它。下面是一个简单的类示例,将进行测试:
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);
}
}
这里是JustMock文档的链接。
免责声明。我是负责JustMock的开发人员之一。
我使用内联函数来避免垃圾收集压力,特别是在处理长时间运行的方法时。假设某人想要获得给定股票代码的2年或市场数据。此外,如果需要,还可以打包大量功能和业务逻辑。
what one does is open a socket connection to the server and loop over the data binding an event to a event. One can think of it the same way as a class is designed, only one is not writing helper methods all over the place that are really only working for one pice of functionality. below is some sample of how this might look like, please note that i am using variables and the "helper" methods are below the finally. In the Finally I nicely remove the event handlers, if my Exchange class would be external/injected i would not have any pending event handler registrated
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;
}
}
您可以看到如下所述的优点,在这里您可以看到一个示例实现。希望这有助于解释它的好处。
我很好奇局部函数到底比lambda快多少,所以我写了一个小基准测试:
[Benchmark]
public void TestLambda()
{
Func<int, int> _Square = (x) => x * x;
_Square(123);
}
[Benchmark]
public void TestLocalFunc()
{
int _Square(int x) => x * x;
_Square(123);
}
结果让我很震惊。
快了4个数量级!
| Method | Mean | Error | StdDev | Median | Allocated |
|-------------- |----------:|----------:|----------:|----------:|----------:|
| TestLambda | 1.4949 ns | 0.1997 ns | 0.0109 ns | 1.4898 ns | - |
| TestLocalFunc | 0.0008 ns | 0.0237 ns | 0.0013 ns | 0.0000 ns | - |
// * Warnings *
ZeroMeasurement
BenchMark.TestLocalFunc: ShortRun -> The method duration is indistinguishable from the empty method duration