2012-05-31 2 views
8

Tôi có các tình huống sau:Gọi một phương pháp chung với nguồn gốc đúng loại

tôi có ba lớp học, chúng ta hãy gọi chúng A, BC. Tất cả chúng có điểm chung là chúng kế thừa từ cùng một giao diện, ISomeInterface và chúng là các lớp được ánh xạ tới các thực thể bằng cách sử dụng Entity Framework.

Tôi có phương thức nhận danh sách đối tượng triển khai giao diện này, nhưng bản thân đối tượng sẽ là các trường hợp A, B hoặc C.

Phương pháp vỏ trông như thế này

public void MyMethod(List<ISomeInterface> entityList) 
{ 
    foreach(var entity in entityList) 
    { 
    ProcessEntity(entity); 
    } 
} 

Bây giờ, vấn đề là với phương pháp ProcessEntity. Đây là một phương pháp chung chung, mà cần phải lấy lại bảng phù hợp với các yếu tố từ cơ sở dữ liệu tùy thuộc vào loại hay tổ chức nào, vì vậy nó trông như thế này:

public void ProcessEntity<T>(T entity) 
{ 
    using(var repository = new DbRepository()) 
    { 
    var set = repository.Set<T>(); 
    ... 
    } 
} 

Vấn đề là dòng var set = repository.Set<T>(); thất bại vì TISomeInterface trong trường hợp này, và không phải là loại thực tế (A, B hoặc C), do đó, nó đưa ra một ngoại lệ không thể liên quan đến loại đã cho, điều này là dễ hiểu.

Vì vậy, câu hỏi của tôi là: Làm thế nào tôi có thể gọi ProcessEntity với loại thực tế của đối tượng bên trong danh sách, và không phải là interfacetype mà họ thực hiện.

Trả lời

13

Bạn có thể áp dụng dynamic từ khóa khi chuyển đối tượng sang ProcessEntity. Trong trường hợp này, loại thực thể thực tế sẽ được xác định trong thời gian chạy.

public void MyMethod(List<ISomeInterface> entityList) 
{ 
    foreach(var entity in entityList) 
    { 
    dynamic obj = entity; 
    ProcessEntity(obj); 
    } 
} 
+1

Điều đó đã làm điều đó. Tôi thay đổi 'ProcessEntity (obj);' thành 'ProcessEntity (obj thành dynamic);', và nó đã làm việc tốt. Sử dụng cho năng động mà tôi không biết.Cảm ơn rất nhiều :) –

+0

@ ØyvindKnobloch-Bråthen yep, tôi thích kiểu thời gian chạy này rất nhiều –

2

Vâng, bạn có thể làm một thủ thuật truy cập giống như và sử dụng workaround sau:

  1. Xác định một phương pháp Process(EntityProcessor ep) trong ISomeInterface
  2. Thực hiện nó trong A cũng giống như ep.ProcessEntity<A>(this) (và theo cùng một cách trong BC)
  3. Thay vì ProcessEntity(entity) trong vòng lặp của bạn, chỉ cần gọi entity.Process(this).

(tên phương pháp có lẽ không sạch, nhưng bạn sẽ nhận được các ý tưởng)

+0

Điều này có hiệu quả, nhưng câu trả lời của lazyberezovsky thì sạch hơn cho tôi vì điều đó có nghĩa là tôi không phải đặt thêm logic vào A, B và C (và có một cách acutally như 20 của các loại, không phải 3;)) –

+0

@ Øyvind: tốt, giải pháp của tôi đòi hỏi nhiều công việc hơn, nhưng nó kiểm tra sự tồn tại của phương pháp cần thiết tại thời gian biên dịch. Đồng thời, nó có thể nhanh hơn một chút. – Vlad

+0

Tôi thấy quan điểm của bạn, nhưng sử dụng năng động, bạn không có một phương pháp cần thiết nào cả, và tôi muốn các lớp A, B và C cũng không có kiến ​​thức về chức năng này. Nó cũng có nghĩa là tôi không phải nhớ để đặt chức năng bổ sung này cho các lớp mới được tạo ra có nghĩa vụ phải làm theo cùng một mẫu. –

2

Bạn có thể sử dụng phản ánh để có được định nghĩa phương pháp chung và sau đó gọi nó, ví dụ:

var method = typeof(ClassContainingProcessEntity) 
    .GetMethod(ProcessEntity) 
    .MakeGenericMethod(entity.GetType); 
method.Invoke(this, entity); 

Bạn có thể cache phương thức theo kiểu, và bạn có thể biên dịch nó theo thời gian chạy bằng cách sử dụng một số loại nhà máy ủy nhiệm nếu hiệu suất là rất quan trọng.

Hoặc bạn có thể sử dụng Visitor pattern

+0

Yup, cả hai đều nên hoạt động, và tôi đã nghĩ đến việc đi tuyến đường phản chiếu nếu tôi không có câu trả lời tốt hơn ở đây. Có vẻ như bản sửa lỗi động này rất nhiều mặc dù sạch hơn. Cảm ơn vì đầu vào của bạn :) –