2009-02-06 44 views
6

Dưới đây là một phiên bản đơn giản của lớp học của tôi:Lớp cơ sở có thể xác định xem một lớp dẫn xuất đã ghi đè thành viên ảo không?

public abstract class Task 
{ 
    private static object LockObject = new object(); 

    protected virtual void UpdateSharedData() { } 
    protected virtual void UpdateNonSharedData() { } 

    public void Method() 
    { 
     lock(LockObject) 
     { 
      UpdateSharedData(); 
     } 
     UpdateNonSharedData(); 
    } 
} 

Tôi đang cố gắng để che giấu mã khóa từ các lớp học có nguồn gốc. Nhưng tôi chỉ muốn lấy khóa nếu lớp dẫn xuất ghi đè UpdateSharedData; nếu không, tôi không muốn phương thức chặn và chờ trên tất cả các cá thể đang chạy khác cập nhật dữ liệu được chia sẻ trước khi cập nhật dữ liệu không được chia sẻ.

Vì vậy, điều dường như (dường như) đối với Phương thức cần làm là kiểm tra xem liệu việc triển khai UpdateSharedData của cá thể hiện tại có làm quá tải việc triển khai lớp cơ sở hay không. Tôi khá chắc chắn điều này là không thể nếu không sử dụng sự phản chiếu, và có lẽ không phải là điều mong muốn để làm điều đó.

Tôi đã nghĩ về một số biện pháp khắc phục điều này, nhưng tất cả họ đang khá lúng túng:

  • Thêm một tài sản bool bảo vệ rằng bộ constructor lớp được thừa kế, và kiểm tra tài sản đó để xem nếu một khóa là cần thiết. Đó là làm một công việc khá khủng khiếp để ẩn mã khóa khỏi các lớp dẫn xuất.
  • Đặt phương thức UpdateSharedData thành thuộc tính ủy nhiệm, có bất kỳ lớp dẫn xuất nào được đặt thuộc tính cho phương thức riêng tư trong hàm tạo của nó và chỉ lấy khóa nếu đại biểu không rỗng. Đó là tốt hơn, nhưng nó vẫn là loại hút.

Trả lời

4

gì nếu bạn định nghĩa một công tác trừu tượng và một giao diện IHasSharedData, sau đó trong phương pháp bạn kiểm tra xem công tác có nguồn gốc thực hiện IHasSharedData trước khi thực hiện Khóa. Chỉ có các lớp thực hiện giao diện cần đợi. Tôi nhận ra rằng điều này tránh trả lời câu hỏi thực tế, nhưng tôi nghĩ rằng nó sẽ là một giải pháp sạch hơn là sử dụng sự phản chiếu. Hy vọng rằng, bạn sẽ tìm thấy một tên tốt hơn cho giao diện phù hợp hơn với những gì các lớp thực sự làm.

public interface IHasSharedData 
{ 
    void UpdateSharedData(); 
} 

public abstract class Task 
{ 
    private static object LockObject = new object(); 

    protected virtual void UpdateNonSharedData() { } 

    public void Method() 
    { 
     if (this is IHasSharedData) 
     { 
      lock(LockObject) 
      { 
       UpdateSharedData(); 
      } 
     } 
     UpdateNonSharedData(); 
    } 
} 

public class SharedDataTask : Task, IHasSharedData 
{ 
    public void UpdateSharedData() 
    { 
     ... 
    } 
} 
+0

Tôi chỉ nhận ra rằng IHasSharedData trông rất giống mã LOLCats. :-) ICanHazSharedData? – tvanfosson

+0

Đó là điều đầu tiên tôi nhận thấy! Sẽ rất khó cho tôi để chống lại việc đặt cho nó một cái tên như thế. Đây chính xác là câu trả lời mà tôi đang tìm kiếm. –

4

Bạn có thể làm việc kiểm tra này với một smidge phản xạ:

bool IsUpdateSharedDataOverridden() 
{ 
    Type t = this.GetType(); 
    MethodInfo m = subType.GetMethod("UpdateSharedData"); 

    return m.DeclaringType == t && m.GetBaseDefinition().DeclaringType == typeof(Task); 
} 
+0

Sẽ chính xác hơn khi so sánh m.DeclaringType trực tiếp thành t. Rất có thể cho hai loại khác nhau có cùng tên. – JaredPar

+0

Điều đó cũng sẽ báo cáo đúng nếu nó được sử dụng "mới" để khai báo lại (không ghi đè) phương pháp. –

+0

Điểm tốt. Đã sửa lỗi cho phù hợp. –

0

Trên thực tế, bạn đang nói về hai đối tượng khác nhau:

public abstract class Task {  
    protected virtual void UpdateNonSharedData() { } 

    public virtual void Method()  
    { 
     UpdateNonSharedData();  
    } 
} 

public abstract class TaskWithSharedData : Task {  
    private static object LockObject = new object();  

    protected virtual void UpdateSharedData() { } 

    public overrides void Method()  
    {  
     lock(LockObject) 
     {   
      UpdateSharedData();  
     } 
     base.Method(); 
    } 
} 

Nhưng, giải pháp lý tưởng hơn sẽ là mẫu chiến lược.

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