在c#中,async应该如何完成调用类的事件访问属性?

时间:2010-12-09 14:46:31

标签: c# events asynchronous lambda

我们一直在使用像这样的lamda事件:

bookMarkClient.wmdeleteCompleted += (s, ea) =>
        {
            if (ea.Result = "Success")
            {
                foreach (BookMark bookMark in BookMarks)
                    {
                        if (bookMarkId == bookMark.bm_id)
                        {
                            BookMarks.Remove(bookMark);
                            OnNotifyPropertyChanged("BookMarks");
                            break;
                        }
                    }                
               }
        };

        bookMarkClient.wmdeleteBookMarkAsync(bookMarkId);

但是根据stackoverflow上的许多答案,这些都无法删除,这样如果我再次调用此代码,我的事件将被触发两次。所以我想删除lambda代码并执行此操作:

//in the class constructor
bookMarkClient.wmdeleteBookMarkCompleted += new EventHandler<wmdeleteBookMarkCompletedEventArgs>(bookMarkClient_wmdeleteBookMarkCompleted);

//Proc on the same class
 void bookMarkClient_wmdeleteBookMarkCompleted(object sender, wmdeleteBookMarkCompletedEventArgs e)
        {
            if (ea.Result = "Success")
            {
                foreach (BookMark bookMark in BookMarks)
                {
                   if (bookMarkId == bookMark.bm_id)
                    {
                        BookMarks.Remove(bookMark);
                        OnNotifyPropertyChanged("BookMarks");
                        break;
                    }
                }
            }

              }

//on button click
bookMarkClient.wmdeleteBookMarkAsync(bookMarkId);

但是:变量bookMarkId不再可用。我理解这是因为lambda事件将变量复制到构造的类中,并在事件持续时间内保持活动状态。 那我该如何做呢?

我已尝试设置私有变量,但测试显示可以在收到回拨之前更改它!这也适用于名为Bookmarks的集合。

注意,这是一个Silverlight客户端,我宁愿不传回事件args中的Id /集合,因为这意味着要重新编写大量的wcf代码。

非常感谢,马特

ps首先发布到堆栈,所以请放轻松...

2 个答案:

答案 0 :(得分:2)

将事件处理程序存储在本地变量中;然后你可以添加和删除相同的事件处理程序:

EventHandler<wmdeleteBookMarkCompletedEventArgs> handler = (s, ea) => { .... }
bookMarkClient.wmdeleteBookMarkCompleted += handler;
// ...
bookMarkClient.wmdeleteBookMarkCompleted -= handler;

或者,lambda表达式只是编译器生成的嵌套类的语法糖。如果您无法将书签ID添加到EventArgs,请通过创建自己的类来模拟lambda:

BookmarkDeletedListener listener = new BookmarkDeletedListener(this, bookMarkId);
bookMarkClient.wmdeleteBookMarkCompleted += listener.DeleteBookmarkCompleted;
bookMarkClient.wmdeleteBookMarkCompleted -= listener.DeleteBookmarkCompleted;

// ...

class BookmarkDeletedListener
{
    public BookmarkDeletedListener(ParentClass parent, string bookmarkId)
    {
        _parent = parent;
        _bookmarkId = bookmarkId;
    }

    public DeleteBookmarkCompleted(object sender, wmdeleteBookMarkCompletedEventArgs e)
    {
        if (ea.Result = "Success")
        {
            foreach (BookMark bookMark in BookMarks)
            {
                if (_bookmarkId == bookMark.bm_id)
                {
                    _parent.BookMarks.Remove(bookMark);
                    _parent.OnNotifyPropertyChanged("BookMarks");
                    break;
                }
            }
        }
    }

    readonly ParentClass _parent;
    readonly string _bookmarkId;
}

答案 1 :(得分:0)

可以删除lambda,AFAIK,只要你抓住它。它甚至可以在被解雇时自行移除:

Action<object, wmdeleteBookMarkCompletedEventArgs> handler;
handler =
    (s, ea) =>
        {
            bookMarkClient.wmdeleteCompleted -= handler;
            if (ea.Result == "Success")
            ...
        };

bookMarkClient.wmdeleteCompleted += handler;