在C#7.0中,您可以声明本地函数,即生活在另一个方法中的函数.这些本地函数可以访问周围方法的局部变量.由于局部变量仅在调用方法时存在,我想知道是否可以将一个局部函数分配给一个委托(它可以比这个方法调用寿命更长).
public static Func<int,int> AssignLocalFunctionToDelegate()
{
int factor;
// Local function
int Triple(int x) => factor * x;
factor = 3;
return Triple;
}
public static void CallTriple()
{
var func = AssignLocalFunctionToDelegate();
int result = func(10);
Console.WriteLine(result); // ==> 30
}
Run Code Online (Sandbox Code Playgroud)
它确实工作!
我的问题是:为什么这有效?这里发生了什么?
前几天,在我的一个实用程序中,ReSharper向我暗示了下面的代码段,声明定义委托的lambda ThreadStart可以转换为本地函数:
public void Start(ThreadPriority threadPriority = ThreadPriority.Lowest)
{
if (!Enabled)
{
_threadCancellationRequested = false;
ThreadStart threadStart = () => NotificationTimer (ref _interval, ref _ignoreDurationThreshold, ref _threadCancellationRequested);
Thread = new Thread(threadStart) {Priority = ThreadPriority.Lowest};
Thread.Start();
}
}
Run Code Online (Sandbox Code Playgroud)
因此转变为:
public void Start(ThreadPriority threadPriority = ThreadPriority.Lowest)
{
if (!Enabled)
{
_threadCancellationRequested = false;
void ThreadStart() => NotificationTimer(ref _interval, ref _ignoreDurationThreshold, ref _threadCancellationRequested);
Thread = new Thread(ThreadStart) {Priority = ThreadPriority.Lowest};
Thread.Start();
}
}
Run Code Online (Sandbox Code Playgroud)
后者相对于前者有什么好处,它只是关于性能吗?
我已经检查了下面的资源,但在我的例子中,好处并不那么明显:
首先,我想说我已经尝试寻找解决方案,我没有找到一个我不必解压缩,添加我的文件夹,然后再拉链.我没有使用任何第三方库.如果可能的话,我想使用system.io.compression来做这个...如果不是,我会使用dotnetzip作为我的最后手段.
TL;博士.我希望能够将包含文件的目录添加到已创建的zip文件中.这可以使用system.io.compression库吗?
编辑:
using (FileStream zipToOpen = new FileStream(zipfile, FileMode.Open))
{
using (ZipArchive archive = new ZipArchive(zipToOpen, ZipArchiveMode.Update))
{
ZipArchiveEntry readmeEntry = archive.CreateEntry("testFolder/");
}
}
Run Code Online (Sandbox Code Playgroud)
所以,使用这段代码我可以在里面创建一个文件夹,但它里面没有任何文件.我现在的问题是我是否必须再次运行此代码才能将我的源文件夹中的每个文件都放到zip文件夹中,或者有更好的方法吗?
当使用一个非常简单的表达式作为创建ILookup的键时,Enumerable.ToLookup<TSource,?TKey> Method (IEnumerable<TSource>,?Func<TSource,?TKey>)我可以使用lambda表达式:
var lk = myItems.ToLookup((x) => x.Name);
Run Code Online (Sandbox Code Playgroud)
或本地功能:
var lk = myItems.ToLookup(ByName);
string ByName(MyClass x)
{
return x.Name;
}
Run Code Online (Sandbox Code Playgroud)
我很好奇这个简单案例是否存在差异.
在他对Local函数vs Lambda C#7.0的回答中,SO用户svick给出了一个很好的论据 - 为什么-in general-局部函数比lambdas更好.
重要的一点是性能的差异:
创建lambda时,必须创建一个委托,在这种情况下这是一个不必要的分配.本地函数实际上只是函数,不需要代理.
但是因为ToLookup()无论如何我们都将它传递给了一个委托.性能还有差异吗?
我可以想象编译器必须为myItems.ToLookup的每次调用创建一个新的委托lambda,而本地方法只需要一个委托实例; 这是真的?
此外,本地函数在捕获局部变量时更有效:lambdas通常将变量捕获到类中,而本地函数可以使用struct(使用ref传递),这又避免了分配.
然而,因为表达不从外部范围使用变量,也不必是封闭的陈述由里德·科普塞和扩大通过埃里克利珀在回答在C#闭包是Lambda表达式?:
lambda可以使用闭包来实现,但它本身不一定是闭包.- Reed Copsey
[...]
一个可以被视为对象的函数只是一个委托.使lambda成为闭包的原因是它捕获了它的外部变量.- Eric Lippert
这多少有些矛盾埃里克利珀自己是他的回答到指定的本地函数来代表 埃里克利珀解释一个局部函数为命名的λ:
本地函数基本上只是一个带有关联名称的lambda.
但这是一个较小的技术细节和lambda/local函数的代表,它们捕获外部范围变量.
这个简单的表达式不是递归的,不是泛型的,也不是迭代器.看起来更好的是一个意见问题.
那么,简单的非捕获,非递归,非泛型和非迭代器lambda表达式和本地函数之间的性能(或其他)是否有任何差异?
想象一下我有这样的代码:
public void Foo()
{
// Do bar work
// Do baz work
// Do foobar work
}
Run Code Online (Sandbox Code Playgroud)
我意识到我可以(而且应该因为它做了不止一件事)将其重构为:
public void Foo()
{
bar();
baz();
foobar();
}
private void bar() { /* do bar work */ }
private void baz() { /* do baz work */ }
private void foobar() { /* do foobar work */ }
Run Code Online (Sandbox Code Playgroud)
但后来我意识到我永远不会在 之外使用这些功能Foo(),因此这些功能只会让主页和自动完成变得混乱。我可以摆脱这个:
public void Foo()
{
bar();
baz();
foobar();
void bar() { /* do bar work */ }
void baz() { …Run Code Online (Sandbox Code Playgroud)