C#-匿名函数和事件处理程序 [英] C# - anonymous functions and event handlers
问题描述
我有以下代码:
public List<IWFResourceInstance> FindStepsByType(IWFResource res)
{
List<IWFResourceInstance> retval = new List<IWFResourceInstance>();
this.FoundStep += delegate(object sender, WalkerStepEventArgs e)
{
if (e.Step.ResourceType == res) retval.Add(e.Step);
};
this.Start();
return retval;
}
注意我如何将事件成员(FoundStep)注册到本地就地匿名函数。
Notice how I register my event member (FoundStep) to local in-place anonymous function.
我的问题是:当函数'FindStepByType'将结束时-匿名函数会自动从事件的委托列表中删除还是我必须手动删除跨出功能之前呢? (以及我该怎么做?)
My question is: when the function 'FindStepByType' will end - will the anonymous function be removed automatically from the delegate list of the event or I have to manually remove it before steping out the function? (and how do I do that?)
我希望我的问题很清楚。
I hope my question was clear.
推荐答案
您的代码有一些问题(您和其他人已经发现了):
Your code has a few problems (some you and others have identified):
- 不能按照编码将匿名委托从事件中删除。
- 匿名委托的寿命比调用该方法的寿命更长,因为您已将其添加到 this 的成员 FoundStep 。
- FindStepsByType 中的每个条目在 FoundStep 中添加另一个匿名委托。
- 匿名委托是一个闭包,有效地延长了 retval 的寿命,即使您停止引用代码中其他地方的 retval ,它仍然由匿名委托持有。
- The anonymous delegate cannot be removed from the event as coded.
- The anonymous delegate will live longer than the life of the method calling it because you've added it to FoundStep which is a member of this.
- Every entry into FindStepsByType adds another anonymous delegate to FoundStep.
- The anonymous delegate is a closure and effectively extends the lifetime of retval, so even if you stop referencing retval elsewhere in your code, it's still held by the anonymous delegate.
要解决此问题,并仍然使用匿名委托,将其分配给局部变量,然后在 finally 块中删除处理程序(如果处理程序抛出异常,则是必需的):
To fix this, and still use an anonymous delegate, assign it to a local variable, and then remove the handler inside a finally block (necessary in case the handler throws an exception):
public List<IWFResourceInstance> FindStepsByType(IWFResource res)
{
List<IWFResourceInstance> retval = new List<IWFResourceInstance>();
EventHandler<WalkerStepEventArgs> handler = (sender, e) =>
{
if (e.Step.ResourceType == res) retval.Add(e.Step);
};
this.FoundStep += handler;
try
{
this.Start();
}
finally
{
this.FoundStep -= handler;
}
return retval;
}
使用C#7.0+,您可以使用本地函数替换匿名委托,从而实现效果相同:
With C# 7.0+ you can replace the anonymous delegate with a local function, achieving the same effect:
public List<IWFResourceInstance> FindStepsByType(IWFResource res)
{
var retval = new List<IWFResourceInstance>();
void Handler(object sender, WalkerStepEventArgs e)
{
if (e.Step.ResourceType == res) retval.Add(e.Step);
}
FoundStep += Handler;
try
{
this.Start();
}
finally
{
FoundStep -= Handler;
}
return retval;
}
这篇关于C#-匿名函数和事件处理程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!