在C#中使用lambda表达式或匿名方法时,我们必须警惕对修改后的闭包陷阱的访问.例如:
foreach (var s in strings)
{
query = query.Where(i => i.Prop == s); // access to modified closure
...
}
Run Code Online (Sandbox Code Playgroud)
由于修改后的闭包,上面的代码将导致Where
查询中的所有子句都基于最终值s
.
正如这里所解释的那样,这是因为上面循环中s
声明的变量foreach
在编译器中被翻译成这样:
string s;
while (enumerator.MoveNext())
{
s = enumerator.Current;
...
}
Run Code Online (Sandbox Code Playgroud)
而不是像这样:
while (enumerator.MoveNext())
{
string s;
s = enumerator.Current;
...
}
Run Code Online (Sandbox Code Playgroud)
正如这里所指出的,在循环外声明变量没有性能优势,在正常情况下,我能想到这样做的唯一原因是你计划在循环范围之外使用变量:
string s;
while (enumerator.MoveNext())
{
s = enumerator.Current;
...
}
var finalString = s;
Run Code Online (Sandbox Code Playgroud)
但是,foreach
循环中定义的变量不能在循环外使用: …
是否可以从事件中取消订阅匿名方法?
如果我订阅这样的事件:
void MyMethod()
{
Console.WriteLine("I did it!");
}
MyEvent += MyMethod;
Run Code Online (Sandbox Code Playgroud)
我可以这样取消订阅:
MyEvent -= MyMethod;
Run Code Online (Sandbox Code Playgroud)
但是如果我使用匿名方法订阅:
MyEvent += delegate(){Console.WriteLine("I did it!");};
Run Code Online (Sandbox Code Playgroud)
是否有可能取消订阅这种匿名方法?如果是这样,怎么样?
一旦编译完成,它们之间是否存在差异:
delegate { x = 0; }
Run Code Online (Sandbox Code Playgroud)
和
() => { x = 0 }
Run Code Online (Sandbox Code Playgroud)
?
我们想要在Control.Invoke中匿名调用委托的语法有点麻烦.
我们已经尝试了许多不同的方法,但都无济于事.
例如:
myControl.Invoke(delegate() { MyMethod(this, new MyEventArgs(someParameter)); });
Run Code Online (Sandbox Code Playgroud)
其中someParameter是此方法的本地
以上将导致编译器错误:
无法将匿名方法转换为类型'System.Delegate',因为它不是委托类型
我认为做这样的事情会很好(lambda做一个yield return):
public IList<T> Find<T>(Expression<Func<T, bool>> expression) where T : class, new()
{
IList<T> list = GetList<T>();
var fun = expression.Compile();
var items = () => {
foreach (var item in list)
if (fun.Invoke(item))
yield return item; // This is not allowed by C#
}
return items.ToList();
}
Run Code Online (Sandbox Code Playgroud)
但是,我发现我不能在匿名方法中使用yield.我想知道为什么.该产量的文档只是说,这是不允许的.
由于不允许,我只创建了List并将项目添加到其中.
我可以找到关于Func <>和Action <>的所有示例都很简单,如下所示,您可以看到它们在技术上如何工作,但我希望看到它们用于解决以前无法解决的问题的示例中只有在一个更复杂的方式,即我知道他们是如何工作的,我可以看到他们是可以解决简洁,功能强大,所以我想了解他们在更大的意义上他们解决什么样的问题,我怎么可能会在使用它们应用程序设计.
您以什么方式(模式)使用Func <>和Action <>来解决实际问题?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestFunc8282
{
class Program
{
static void Main(string[] args)
{
//func with delegate
Func<string, string> convert = delegate(string s)
{
return s.ToUpper();
};
//func with lambda
Func<string, string> convert2 = s => s.Substring(3, 10);
//action
Action<int,string> recordIt = (i,title) =>
{
Console.WriteLine("--- {0}:",title);
Console.WriteLine("Adding five to {0}:", i);
Console.WriteLine(i + 5);
};
Console.WriteLine(convert("This is the first test.")); …
Run Code Online (Sandbox Code Playgroud) 我想知道这是否真的有效?
private void RegisterKeyChanged(T item)
{
item.OnKeyChanged += (o, k) => ChangeItemKey((T)o, k);
}
private void UnRegisterKeyChanged(T item)
{
item.OnKeyChanged -= (o, k) => ChangeItemKey((T)o, k);
}
Run Code Online (Sandbox Code Playgroud)
编译器如何知道事件处理程序是否相同?这甚至是推荐的吗?
我有以下代码:
class myClass
{
private delegate string myDelegate(Object bj);
protected void method()
{
myDelegate build = delegate(Object bj)
{
var letters= string.Empty;
if (someCondition)
return build(some_obj); //This line seems to choke the compiler
else string.Empty;
};
......
}
}
Run Code Online (Sandbox Code Playgroud)
有没有其他方法可以在C#中设置匿名方法,以便它可以调用自己?
Stack Overflow正在回答很多问题,成员们指定如何使用lambda表达式解决这些现实世界/时间问题.
我们是否过度使用它,我们是否在考虑使用lambda表达式对性能的影响?
我发现了一些文章,探讨了lambda与匿名委托vs for
/ foreach
循环对不同结果的性能影响
选择合适的解决方案时,评估标准应该是什么?除了明显的原因,它使用lambda时更简洁的代码和可读性.
我正在尝试创建一个可以创建一个Action的函数来增加传入的整数.但是我的第一次尝试是给出了一个错误"不能在匿名方法体内使用ref或out参数".
public static class IntEx {
public static Action CreateIncrementer(ref int reference) {
return () => {
reference += 1;
};
}
}
Run Code Online (Sandbox Code Playgroud)
我理解为什么编译器不喜欢这个,但是我希望有一个优雅的方法来提供一个可以指向任何整数的漂亮的增量器工厂.我看到这样做的唯一方法如下:
public static class IntEx {
public static Action CreateIncrementer(Func<int> getter, Action<int> setter) {
return () => setter(getter() + 1);
}
}
Run Code Online (Sandbox Code Playgroud)
但当然这对来电者来说更是一种痛苦; 要求调用者创建两个lambda而不是仅仅传入一个引用.有没有更优雅的方式来提供这个功能,或者我只需要忍受双lambda选项?