2015-03-09 18 views
8

Tôi đang sử dụng lớp WeakEventManager<TEventSource, TEventArgs> để đăng ký các sự kiện trong C#. Đăng ký sự kiện hoạt động tốt, tuy nhiên gọi WeakEventManager<TEventSource, TEventArgs>.RemoveHandler từ một Task không phải lúc nào cũng xóa trình xử lý - phần lớn (nhưng không phải tất cả) trong khoảng thời gian trình xử lý vẫn được thực hiện khi sự kiện kích hoạt.WeakEventManager RemoveHandler không phải lúc nào cũng hoạt động khi được gọi không đồng bộ

Điều này được minh họa trong ví dụ sau.

public class EventSource 
{ 
    public event EventHandler Fired = delegate { }; 

    public void FireEvent() 
    { 
     Fired(this, EventArgs.Empty); 
    } 
} 

class Program 
{ 
    private static bool added, removed, handled; 

    static void Main(string[] args) 
    { 
     for (int i = 1; i <= 100; i++) 
     { 
      added = removed = handled = false; 

      var source = new EventSource(); 

      AddHandlerAsync(source).Wait(); 

      RemoveHandlerAsync(source).Wait(); 

      source.FireEvent(); 

      if (removed && handled) Console.WriteLine("Event handled after removal!"); 
      else     Console.WriteLine("----------------------------"); 
     } 

     Console.ReadKey(); 
    } 

    private async static Task AddHandlerAsync(EventSource source) 
    { 
     await Task.Run(() => 
     { 
      System.Windows.WeakEventManager<EventSource, EventArgs>.AddHandler(source, "Fired", HandleEvent); 
      added = true; 
     }); 
    } 

    private async static Task RemoveHandlerAsync(EventSource source) 
    { 
     await Task.Run(() => 
     { 
      System.Windows.WeakEventManager<EventSource, EventArgs>.RemoveHandler(source, "Fired", HandleEvent); 
      removed = true; 
     }); 
    } 

    private static void HandleEvent(object sender, EventArgs e) 
    { 
     handled = true; 
    } 
} 

Trình xử lý được gỡ bỏ mọi lúc, tuy nhiên trong hầu hết các trường hợp, sự kiện vẫn được xử lý.

Tôi có mắc lỗi theo cách mà các phương pháp này được gọi không? Những phương thức này có hỗ trợ được gọi là không đồng bộ không? Có cách tiếp cận thay thế nào có hiệu quả không?

Rất cám ơn sự giúp đỡ của bạn trước.

Trả lời

6

Đó là vì WeakEventManager 's được lưu trữ trong một hiện tại WeakEventTable mà khởi tạo cho thread hiện hành (source):

[ThreadStatic] 
private static WeakEventTable _currentTable; // one table per thread 

Và bạn sử dụng hồ bơi thread nhiệm vụ sheduler là sheduler mặc định. Nó gọi AddHandlerRemoveHandler trên cùng một luồng đôi khi. Nhưng đôi khi nó gọi RemoveHandler trên một chủ đề khác và bạn có một số khác WeakEventManager mà không cần yêu cầu EventSource.

LƯU Ý: Nếu loại thừa hưởng từ DispatcherObject thì trường hợp của loại này phụ thuộc vào chuỗi mà chúng được tạo. Nếu một DispatcherObject là singleton thì nó được tạo ra một cho mỗi chủ đề.

Vì vậy, nếu bạn thấy DispatcherObject thì hãy gọi các phương thức của nó chỉ từ chuỗi được tạo. Nếu không, bạn sẽ có vấn đề.

+0

Cảm ơn, điều đó giải thích lý do tôi thấy hành vi này. Làm thế nào tôi sẽ thay đổi cách tôi gọi Add/RemoveHandler để xử lý được loại bỏ trên cùng một thread? – mickeyt

+0

Sử dụng 'Application.Current.Dispatcher' để gọi các phương thức' AddHandler' và 'RemoveHandler'. –

+0

Không có 'Application.Current' trong ví dụ này. Cảm ơn bạn đã tip về 'DispatcherObject' mặc dù - rất hữu ích! – mickeyt

Các vấn đề liên quan