我有以下代码:
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) 注册到本地就地匿名函数的。
我的问题是:“FindStepByType”函数何时结束——匿名函数会自动从事件的委托(delegate)列表中删除,还是我必须在退出该函数之前手动删除它? (我该怎么做?)
我希望我的问题很清楚。
最佳答案
您的代码有一些问题(您和其他人已经确定了一些问题):
- 无法按照编码从事件中删除匿名委托(delegate)。
- 匿名委托(delegate)的生命周期将比调用它的方法的生命周期长,因为您已将它添加到this 的成员FoundStep。
- 每次进入 FindStepsByType 都会向 FoundStep 添加另一个匿名委托(delegate)。
- 匿名委托(delegate)是一个闭包,有效地延长了 retval 的生命周期,因此即使您停止在代码的其他地方引用 retval,它仍然由匿名委托(delegate)持有.
要解决这个问题,并且仍然使用匿名委托(delegate),将其分配给一个局部变量,然后删除 finally block 中的处理程序(在处理程序抛出异常的情况下是必需的):
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+ 中,您可以将匿名委托(delegate)替换为本地函数,从而达到相同的效果:
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# - 匿名函数和事件处理程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1389543/