Không có phương pháp đơn giản để đạt được điều này.
phương pháp ưa thích:
Tôi không thấy lý do tại sao bạn không thể lưu các đại biểu. Bạn không cần phải lưu dụ như một số trường. Nó có thể là biến cục bộ được xử lý bởi trình xử lý sự kiện ẩn danh của bạn:
EventHandler<TypeOfEventArgs> handler = null;
handler = (s, e) =>
{
// Do whatever you need to do here
// Remove event:
foo.Event -= handler;
}
foo.Event += handler;
Tôi không thể nghĩ ra một trường hợp duy nhất mà bạn không thể sử dụng.
Cách tiếp cận thay thế mà không lưu đại biểu:
Tuy nhiên, nếu bạn có kịch bản như vậy, sẽ rất phức tạp.
Bạn cần tìm đại biểu đã được thêm làm người xử lý cho sự kiện. Bởi vì bạn đã không lưu nó, nó là khá khó khăn để có được nó. Không có this
để có được một đại biểu của phương pháp hiện đang thực hiện.
Bạn không thể sử dụng GetInvocationList()
trong sự kiện, vì việc truy cập sự kiện bên ngoài lớp được xác định trong bị hạn chế thêm và xóa trình xử lý, tức là +=
và -=
.
Không thể tạo đại biểu mới. Trong khi bạn có thể truy cập đối tượng MethodInfo
xác định phương thức ẩn danh của bạn, bạn không thể truy cập vào cá thể của lớp mà phương thức được khai báo. Lớp này được trình biên dịch tạo tự động và gọi this
bên trong phương thức nặc danh sẽ trả về Ví dụ của lớp mà phương pháp thông thường của bạn được định nghĩa.
Cách duy nhất tôi thấy là hoạt động là tìm trường - nếu có - sự kiện đó sử dụng và gọi GetInvocationList()
trên đó. Các mã sau đây chứng tỏ điều này với một lớp giả:
void Main()
{
var foo = new Foo();
foo.Bar += (s, e) => {
Console.WriteLine("Executed");
var self = new StackFrame().GetMethod();
var eventField = foo.GetType()
.GetField("Bar", BindingFlags.NonPublic |
BindingFlags.Instance);
if(eventField == null)
return;
var eventValue = eventField.GetValue(foo) as EventHandler;
if(eventValue == null)
return;
var eventHandler = eventValue.GetInvocationList()
.OfType<EventHandler>()
.FirstOrDefault(x => x.Method == self)
as EventHandler;
if(eventHandler != null)
foo.Bar -= eventHandler;
};
foo.RaiseBar();
foo.RaiseBar();
}
public class Foo
{
public event EventHandler Bar;
public void RaiseBar()
{
var handler = Bar;
if(handler != null)
handler(this, EventArgs.Empty);
}
}
Xin lưu ý rằng chuỗi "Bar"
được truyền cho GetField
cần phải là tên chính xác của lĩnh vực được sử dụng bởi sự kiện này. Điều này dẫn đến hai vấn đề:
- Trường có thể được đặt tên khác, ví dụ: khi sử dụng triển khai sự kiện rõ ràng. Bạn cần tự tìm ra tên trường.
- Có thể không có trường nào cả. Điều này xảy ra nếu sự kiện sử dụng triển khai sự kiện rõ ràng và chỉ ủy quyền cho một sự kiện khác hoặc lưu trữ các đại biểu theo một cách khác.
Kết luận:
Phương pháp thay thế dựa vào chi tiết thực hiện, do đó, không sử dụng nó nếu bạn có thể tránh nó.
Có một vài mẫu trên mạng cho phép bạn để đăng ký vào các sự kiện trong một * loosley cùng * chiều. Hãy xem [this] (http://martinfowler.com/eaaDev/EventAggregator.html). Nó mô tả cách đăng ký/hủy đăng ký một trình tổng hợp sự kiện (trong trường hợp này là về màn hình). Trình tổng hợp thực sự tạo ra các tham chiếu giữa các đối tượng. Có rất nhiều cách triển khai khác nhau. Người tôi thích được thực hiện trong [Caliburn.Micro] (http://www.mindscapehq.com/blog/index.php/2012/02/01/caliburn-micro-part-4-the-event-aggregator/) . –