2008-11-14 26 views
38

Tôi có một lớp tĩnh mà tôi muốn nâng một sự kiện như một phần của khối try catch trong một phương thức tĩnh của lớp đó.Làm thế nào để nâng cao sự kiện tùy chỉnh từ một lớp tĩnh

Ví dụ trong phương pháp này, tôi muốn tăng sự kiện tùy chỉnh trong phần bắt.

public static void saveMyMessage(String message) 
{ 
    try 
    { 
     //Do Database stuff 
    } 
    catch (Exception e) 
     { 
       //Raise custom event here 
     } 
} 

Cảm ơn bạn.

Trả lời

88

Quan trọng: hãy cẩn thận khi đăng ký sự kiện tĩnh từ các phiên bản. Tĩnh-tĩnh là tốt, nhưng một thuê bao từ một sự kiện tĩnh đến một trình xử lý thể hiện là một cách tuyệt vời (đọc: rất nguy hiểm) để giữ cho cá thể đó tồn tại mãi mãi. GC sẽ thấy liên kết, và sẽ không thu thập cá thể trừ khi bạn hủy đăng ký (hoặc sử dụng một cái gì đó như một WeakReference).

Các mô hình để tạo sự kiện tĩnh cũng giống như sự kiện isntance, chỉ với static:

public static event EventHandler SomeEvent; 

Để làm cho cuộc sống dễ dàng hơn (tái kiểm tra null), một thủ thuật hữu ích ở đây là thêm một handler tầm thường:

public static event EventHandler SomeEvent = delegate {}; 

Sau đó, bạn chỉ có thể gọi nó mà không null-kiểm tra:

SomeEvent(null, EventArgs.Empty); 

Lưu ý rằng vì các cá thể đại diện là không thay đổi, và tham chiếu là an toàn luồng, không bao giờ có điều kiện chủng tộc ở đây và không cần khóa ... ai đã đăng ký khi chúng tôi không tham chiếu.

(điều chỉnh cho sự kiện của riêng bạn-args, v.v.). Thủ thuật này áp dụng như nhau đối với các sự kiện cụ thể.

+0

Khi đọc câu trả lời của bạn, bạn đã nói, "đăng ký từ một sự kiện tĩnh tới trình xử lý thể hiện là cách tuyệt vời để giữ cho cá thể đó tồn tại mãi mãi", tôi cho rằng điều này sẽ không phải lúc nào cũng tối ưu. Nếu, nói, tôi đang sử dụng một lớp tĩnh để lưu trữ các thiết lập Form trong khi nó đang chạy, điều này sẽ không phải là một điều xấu vì nó tĩnh, và không thể có nhiều bản sao? (Lập trình viên mới, tha thứ cho thuật ngữ xấu) – Josh

+0

@Josh "cách tuyệt vời" có nghĩa là "một cách thực sự nguy hiểm" - tôi đã làm rõ điều đó. Nếu bạn chỉ có một đăng ký, nó không phải là một vấn đề lớn bất kể trường hợp so với tĩnh. Phần nguy hiểm xuất hiện khi mọi cá thể đăng ký (nói) với sự kiện tĩnh hoặc sự kiện trên đối tượng tồn tại lâu dài và không bao giờ hủy đăng ký. Hey mau: guốc bộ nhớ. –

+1

"đăng ký từ một sự kiện tĩnh tới trình xử lý đối tượng" có được viết như vậy theo mục đích không? Tôi tin rằng nó nên được "đăng ký từ một xử lý dụ một sự kiện tĩnh" thay thế. –

0

Lưu ý: VS2008, C#

Chỉ cần tuyên bố một sự kiện như bình thường trong lớp tĩnh, nhưng hãy chắc chắn để đánh dấu sự kiện này như tĩnh:

public static event EventHandler Work; 

Sau đó chỉ cần đăng ký với nó như bạn bình thường.

+0

Re "như bình thường" - bạn cần thận trọng hơn với các sự kiện tĩnh, đặc biệt là hủy đăng ký lại. Điều đó sẽ làm việc trong bất kỳ phiên bản nào của C# btw. –

10

sự kiện của bạn cũng sẽ cần phải được tĩnh:

public class ErrorEventArgs : EventArgs 
{ 
    private Exception error; 
    private string message; 

    public ErrorEventArgs(Exception ex, string msg) 
    { 
     error = ex; 
     message = msg; 
    } 

    public Exception Error 
    { 
     get { return error; } 
    } 

    public string Message 
    { 
     get { return message; } 
    } 
} 

public static class Service 
{ 
    public static EventHandler<ErrorEventArgs> OnError; 

    public static void SaveMyMessage(String message) 
    { 
      EventHandler<ErrorEventArgs> errorEvent = OnError; 
     if (errorEvent != null) 
     { 
      errorEvent(null, new ErrorEventArgs(null, message)); 
     } 
    } 
} 

Và Cách sử dụng:

public class Test 
{ 
    public void OnError(object sender, ErrorEventArgs args) 
    { 
     Console.WriteLine(args.Message); 
    } 
} 

Test t = new Test(); 
Service.OnError += t.OnError; 
Service.SaveMyMessage("Test message"); 
+0

+1 đã quá lâu kể từ khi tôi phải viết xử lý sự kiện, tôi thậm chí không thể nhớ cú pháp của nó. Rõ ràng bởi vì tôi chỉ có thể nghĩ về cú pháp 2.0 (lần cuối cùng tôi đã phải viết một cú pháp) và quên họ thêm điều này vào 3,5 –

6

Một số folks đã đề nghị lên các ví dụ mã, chỉ cần không bắn một sự kiện sử dụng mã như:

if(null != ExampleEvent) 
{ 
    ExampleEvent(/* put parameters here, for events: sender, eventArgs */); 
} 

vì điều này chứa trạng thái cuộc đua khi bạn kiểm tra sự kiện cho giá trị rỗng và khi bạn thực sự kích hoạt sự kiện. Thay vì sử dụng một biến thể đơn giản:

MyEvent exampleEventCopy = ExampleEvent; 
if(null != exampleEventCopy) 
{ 
    exampleEventCopy(/* put parameters here, for events: sender, eventArgs */); 
} 

này sẽ sao chép bất kỳ thuê bao sự kiện vào exampleEventCopy, sau đó bạn có thể sử dụng như là một phiên bản địa phương duy nhất của sự kiện công cộng mà không phải lo lắng về bất cứ điều kiện chủng tộc (Về cơ bản, nó có thể là một chuỗi khác có thể làm trống bạn ngay sau khi bạn đã kiểm tra sự kiện công khai cho null và tiếp tục xóa tất cả người đăng ký khỏi sự kiện, khiến cho sự kiện tiếp theo bị ném ngoại lệ, bằng cách sử dụng bản sao cục bộ, bạn tránh khả năng xóa một người đăng ký khác vì không có cách nào họ có thể truy cập vào biến địa phương).

+7

Một sửa chữa dễ dàng hơn là: public static event EventHandler Work = delegate {}; Bây giờ nó không bao giờ là rỗng và bạn chỉ có thể gọi nó. Hơi lười, nhưng không đủ để làm tổn thương. –

+1

@Mark So với việc sao chép danh sách đại biểu và thực hiện kiểm tra không, tôi nghĩ có một đại biểu "không làm gì" nhanh hơn và đơn giản hơn. Cảm ơn câu trả lời ở trên. – MindJuice

0

Chỉ cần thêm "Đại biểu là không thay đổi" Vì vậy, như được hiển thị trong ví dụ trên dòng sau có được một bản sao của đại biểu.

EventHandler<ErrorEventArgs> errorEvent = OnError; 
Các vấn đề liên quan