使用匿名委托处理事件

时间:2010-01-27 13:27:21

标签: .net events anonymous-delegates

为了记录:我发现了一个类似的问题here但我必须详细说明这个问题。

我的具体情况是:

在Silverlight 4中,myFrameworkElement.FindName("otherElementName")方法现在似乎工作正常,但我遇到了问题。当元素尚未明显添加到可视化树时,它仍会返回null

但现在我需要在自定义DependencyProperty处理程序的PropertyChangedCallback UserControl中使用此功能。在此范围内,尚不确定UserControl是否已添加到可视树中。但我必须对树中的另一个元素执行某个操作。当元素已经可用时,它现在可以而且应该立即完成。如果没有,必须在可用时立即完成。所以我提出了这个扩展方法,我可以像这样调用:

myFrameworkElement.FindNameEnsured("otherElementName",
    result => this.DoSomethingWith(result));

扩展方法的代码如下:

    static public void FindNameEnsured(this FrameworkElement self,
            string name, Action<object> resultAction)
    {
        if (self != null && resultAction != null)
        {
            object result = self.FindName(name);

            if (result != null)
            {
                resultAction(result);
            }
            else
            {
                RoutedEventHandler handler = null;
                handler = (sender, e) =>
                     {
                         result = self.FindName(name);
                         resultAction(result);

                         self.Loaded -= handler;
                     };

                self.Loaded += handler;
            }
        }

如您所见,我必须使用匿名委托,因为我需要处理程序内的nameresultAction的值。然后,我取消订阅处理程序内部的事件,因为我是一个聪明而干净的家伙,并希望不泄漏。我也不想用一些奇特的WeakEventFactories或者类似的东西打破这里的任何苍蝇。

到目前为止,这项工作顺利进行。但我有一些问题。

  1. 这通常是一个足够干净的方法来取消订阅处理程序内的事件处理程序吗?或者最终会杀死一只无辜的小狗?
  2. 由于在匿名委托中使用外部范围变量,可能会出现一些泄漏等问题吗?
  3. 是否会出现导致我“错过”Loaded事件的线程同步问题?在这种特殊情况下,只应涉及Silverlight的UI调度程序线程。但是如果它仍然是一个问题,并且/或者如果我需要在非UI相关场景中使用类似的功能,那么f1x0r的最佳方法是什么呢?
  4. 感谢您的耐心和时间阅读我冗长的阐述。 ; - )

1 个答案:

答案 0 :(得分:2)

  1. 这应该没事,虽然有点痛苦。 LINQ to Rx有一个更好的取消订阅的想法 - 当你订阅时,你得到一个IDisposable,当你处理它时取消订阅。但这并不适合现有的事件模型。
  2. 我认为在这种特殊情况下你不会有任何泄漏 - 有一些边缘条件,在同一范围内使用变量的两个不同的匿名函数每个都可以最终捕获它们不需要的变量,但它确实是一个边缘案例。
  3. 您必须提供有关假设情况的更详细信息 - 您完全担心的事情,事件的实施方式等。