2010-01-07 44 views
6

Lưu ý: Tôi đã chỉnh sửa câu hỏi này để giúp những người khác có cùng sự cố nhận trợ giúp ở đây dễ dàng hơn. Để xem câu hỏi gốc phù hợp hơn với một số câu trả lời, hãy kiểm tra lịch sử chỉnh sửa.Sự cố với sự kiện "chuỗi"

Trong một dự án tôi có một lớp ExecutionManager có thể chứa nhiều trường hợp của ExecutionSlot. Lớp ExecutionSlot có một số trường sự kiện công khai như sau:

public event EventHandlers.ObjectEventHandler<IPlugin> ExecuteCompleted; 

Đối với mỗi sự kiện này có sự kiện phù hợp trên ExecutionManager. Hành vi mong muốn là mỗi khi ExecutionSlot tăng một sự kiện, sự kiện phù hợp cũng được nâng lên trên ExecutionManager chứa.

Giải pháp implmented là bất cứ khi nào một ExecutionSlot đã được thêm vào một ExecutionManager các ExectionManager sẽ thêm các sự kiện riêng của mình để của ExecutionSlot như thế này:

executionSlot.ExecuteCompleted += ExecuteCompleted; 

Không cần phải nêu ra để loại bỏ một ExecutionSlot, vì vậy các sự kiện không bao giờ bị xóa.

Sự cố là sự kiện trên ExecutionManager không được nâng lên. Sau khi xác nhận rằng một sự kiện đã được reaised bởi một ExecutionSlot tôi phát hiện ra rằng việc thay đổi dòng trên như sau cố định vấn đề:

executionSlot.ExecuteCompleted += (sender, eventArgs) => ExecuteCompleted(sender, eventArgs); 

Và tôi không thể tìm ra lý do tại sao, vì vậy câu hỏi của tôi là, những gì khác biệt là .

Lý do cho sự khác biệt này là lần đầu tiên thêm người nghe hiện tại của sự kiện ExecutionManager vào sự kiện của ExecutionSlot. Vì vậy, bất kỳ người nghe nào được thêm vào sau sẽ không được gọi khi sự kiện được nâng lên. Ngược lại, giải pháp thứ hai sử dụng lambda để nâng cao sự kiện của ExecutionManager, điều đó có nghĩa là người nghe tại thời điểm sự kiện sẽ được gọi.

Lý do cơ bản cho giải pháp đầu tiên bị lỗi, là các đại biểu không thay đổi được. Vì vậy, khi bạn thêm một đại biểu mới vào và sự kiện, bạn đang thực sự tạo ra một đại biểu mới có chứa các đại biểu hiện có và bổ sung. Vì vậy, bất kỳ tham chiếu đến các đại biểu được thực hiện trước sẽ không chứa các đại biểu mới được bổ sung.

+1

có thể hoàn nguyên các chỉnh sửa của bạn về câu hỏi ban đầu của bạn, sau đó đặt một câu hỏi khác và trả lời nó, với các tham chiếu qua lại? – JoelFan

+0

Tôi thấy điểm giữ văn bản gốc vì đó là câu trả lời ở đây. Nhưng vì văn bản gốc không đủ rõ ràng, tôi cảm thấy rằng văn bản mới sẽ là trợ giúp tốt hơn cho người khác, so với hầu hết các câu hỏi trùng lặp. –

Trả lời

3

nhìn vào this other post on stackoverflow

b += (s, e) => a(s, e); 

là không giống như

b += a; 

Nó gắn thêm các nội dung hiện tại của a đến b, vì vậy nếu nhiều hơn sau xử lý tranh thủ với một, điều này sẽ không khiến chúng được gọi khi b được kích hoạt

+0

Đó là nơi a và b là các biến - trong trường hợp này nó là tên của một phương thức, do đó, nó không thực sự chụp bất cứ điều gì khác với tham chiếu "này" (cũng sẽ được nắm bắt hoàn toàn ở dạng thứ hai). –

+1

Frig, bạn hoàn toàn đúng. Các đại biểu bất biến ngu ngốc;) Điều đó giải thích nó một cách hoàn hảo, các đối tượng hooking lên trên sự kiện cuối cùng trong chuỗi sau đó sẽ không được gọi. Cảm ơn –

+1

Được rồi, tôi đã giả sử * rằng ExecuteCompleted là một phương thức. Nếu nó thực sự là một biến (ví dụ: thông qua một sự kiện giống như trường) thì điều đó thực sự có ý nghĩa. Một ví dụ khác trong đó có một ví dụ hoàn chỉnh hợp lý có thể đã giúp :) –

4

Một ý tưởng ... có lẽ đâu đó là trong mã của bạn, nơi bạn đang làm:

executionSlot.ExecuteCompleted -= ExecuteCompleted; 

đó sẽ huỷ đăng ký sự kiện này nếu bạn sử dụng cú pháp đăng ký ban đầu của bạn, nhưng sẽ không loại bỏ nó một lần bạn đã thực hiện của bạn thay đổi.

+0

Điều đó không thể thực hiện được, sẽ không tạo ra cùng một cá thể đối tượng đại biểu. Mục tiêu là khác nhau. –

+0

Cái gì? Tôi nghĩ chúng ta đang nói cùng một điều! ??? – JoelFan

+0

Cảm ơn bạn đã đề xuất, không may là không có đăng ký. Nhưng một trong những lý do tôi thích mã thứ hai để làm việc là tôi có thể cần nó trong một phiên bản sau của chương trình, và tôi thực sự không muốn viết ra hàm xử lý, vì có nhiều hơn một vài sự kiện. Tôi sẽ cố gắng và thêm một chút thông tin trong câu hỏi. –

4

EDIT: Câu trả lời này giả định rằng ExecuteCompleted là phương thức . Vì đây thực sự là trường , điều này thay đổi hoàn toàn mọi thứ. Tôi sẽ để lại câu trả lời ở đây vì lợi ích của hậu thế.

Phiên bản đầu tiên thêm trình xử lý sự kiện với đại biểu được tạo từ phương thức được tạo tự động mà lần lượt chỉ gọi ExecuteCompleted. Nó giống như thế này:

private void <>AutogeneratedMethodWithUnspeakableName(object sender, EventArgs e) 
{ 
    ExecuteCompleted(e); 
} 
... 
executionSlot.ExecuteCompleted += <>AutogeneratedMethodWithUnspeakableName; 

Phiên bản thứ hai thêm trình xử lý sự kiện với đại biểu được tạo trực tiếp từ phương thức ExecuteCompleted.

Về cơ bản, biểu mẫu đầu tiên là thêm một cấp chuyển hướng. Điều này thường không tạo ra bất kỳ sự khác biệt nào, ngoại trừ việc hủy đăng ký như JoelFan đã đề cập. Tôi sẽ đoán đó là vấn đề.

Lớp nâng cao sự kiện có thể phản ánh các trình xử lý được đính kèm và xem tên phương thức, phản ứng khác nhau trong trường hợp cụ thể này - nhưng rất khó xảy ra.

+0

Cảm ơn bạn đã đề xuất, không may là không có hủy đăng ký. Nhưng một trong những lý do tôi thích mã thứ hai để làm việc là tôi có thể cần nó trong một phiên bản sau của chương trình, và tôi thực sự không muốn viết ra hàm xử lý, vì có nhiều hơn một vài sự kiện. Và tôi cũng không sử dụng sự phản chiếu trong lớp. Tôi sẽ cố gắng và thêm một chút thông tin trong câu hỏi. –

+0

@Lillemanden: Nếu bạn có thể đưa ra một ví dụ ngắn nhưng đầy đủ thể hiện vấn đề, tôi chắc chắn chúng tôi sẽ có thể sắp xếp nó ra. –

+0

@Jon Skeet: Tôi khá chắc chắn rằng Protron đã đóng đinh nó. Vì các đại biểu là bất biến, một đại biểu multicast mới được tạo ra mỗi khi bạn sử dụng "+ =". Vì vậy, khi một cái gì đó đăng ký với sự kiện cuối cùng trong chuỗi một cá thể đại biểu mới được tạo ra, nhưng trường hợp đó không được thêm vào sự kiện executionSlot.ExecuteCompleted. Ít nhất đó là AFAIK, hy vọng nó có ý nghĩa. –

0

Tôi tin rằng những gì đang xảy ra ở đây là một số loại đối tượng tạm thời đang được tạo trong ví dụ đầu tiên với trình xử lý sự kiện trống đang được gọi, nhưng không có gì.

Ví dụ thứ hai, mà bạn nói là hoạt động, là một trình xử lý sự kiện trên đối tượng của bạn bằng mã thực. Không hoàn toàn chắc chắn những gì đang xảy ra ở đó mặc dù, nhưng đó là dự đoán tốt nhất của tôi.

Chắc chắn ví dụ đầu tiên có mùi xấu, vì nó sử dụng các biểu thức lambda để làm xáo trộn ý nghĩa mà không có giá trị thực được thêm vào.

+0

Nó có thể không tạo ra một đối tượng, trên thực tế - tôi mong đợi trình biên dịch thêm một phương thức thể hiện vào lớp hiện tại, vì nó không nắm bắt bất cứ thứ gì khác ngoài "this". –

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