2013-04-12 22 views
5

Đây là một phần của mã của tôi mà tôi cần giúp đỡ với:Bị mắc kẹt trên generics và giao diện. Cần giải pháp dựa trên mã, có thể thiết kế lại giao diện

// simple service locator 
public class ServiceManager<TSvc> : IServiceManager<TSvc> where TSvc: class, IService 
{ 
    private Dictionary<object, TSvc> services; 

    public void RegisterService(TSvc service) 
    { 
     // omitted code here 
     this.services.Add(service.GetType(), service); // dictionary 
    } 
    public T GetService<T>() where T : TSvc 
    { 
     T result = default(T); 

     TSvc bufResult = null; 
     if (this.services.TryGetValue(typeof(T), out bufResult)) 
      result = (T)bufResult; 

     return result; 
    } 
    public TSvc GetService(Type serviceType) 
    { 
     TSvc result = null; 

     this.services.TryGetValue(serviceType, out result); 

     return result; 
    } 
} 

Sau đó giao diện tên miền của tôi:

public interface IItem 
{ 
    string Name { get; set; } 
} 
public interface IRepository<TModel> where TModel : IItem 
{ 
    new IEnumerable<TModel> GetItems(); 
    void InsertItem(TModel item); 
    void UpdateItem(TModel item); 
    void DeleteItem(TModel item); 
} 
public interface IService<TModel> where TModel : IItem 
{ 
    IRepository<TModel> Repository { get; } 
} 

Sau đó, một số các lớp miền của tôi:

public class Book: IItem 
{ 
    public string Name { get; set; } 
} 
public class BookRepo: IRepository<Book> 
{ 
    new IEnumerable<Book> GetItems(); 
    void InsertItem(Book item); 
    void UpdateItem(Book item); 
    void DeleteItem(Book item); 
} 
public class BookService: IService<Book> 
{ 
    IRepository<Book> IService<Book>.Repository { get { return this.Repository; } } 
    BookRepo Repository { get; set;} 
} 

Bây giờ, nếu tôi muốn sử dụng 'BookService' và làm điều gì đó với nó, tôi có thể lấy từ trình định vị dịch vụ như sau:

public void DoSomething() 
{ 
    var bookService = serviceManager.GetService<BookService>(); 
    bookService.Repository.Insert(new Book()); 
} 

Nhưng vấn đề là loại dịch vụ chỉ được biết khi chạy (ví dụ: lựa chọn từ combobox). Vậy, phương thức DoSomething trông như thế nào?

public void DoSomething() 
{ 
    var typeOfService = combobox.SelectedValue.GetType(); // cbx of services 
    // ??? make use of serviceManager and typeOfService to get appropriate 'service' 
    service.Repository.Insert(/*new IITem here*/); 
} 

Ngoài ra, tôi muốn biết làm thế nào bạn sẽ kết nối IService-IService<TModel> ... nó thậm chí có thể nhận được các giải pháp, nhưng tôi không có ý tưởng như thế nào. Giao diện IService của tôi trống cho thời điểm này ...

Tôi thực sự sẽ đánh giá cao thời gian của bạn. Vui lòng cho tôi biết nếu có điều gì đó không rõ ràng! Cảm ơn bạn!

Cập nhật: Dựa trên câu trả lời của bạn, tôi đoán phần phản ánh có thể được tham gia (cái gì đó như NSGaga chỉ ra), nhưng vẫn còn, mà không kết nối IServiceIService<TModel> tôi không thể đạt được những gì tôi muốn. Ai có ý tưởng làm thế nào để thiết kế lại điều này?

+0

Có lý do nào bạn không sử dụng Vùng chứa phụ thuộc hiện tại chẳng hạn như Ninject hoặc Unity thay vì xây dựng của riêng bạn không? – Kenneth

+0

@Kenneth: Lý do học tập là đủ? :) Là một cơ hội tốt để học thao tác giao diện và sử dụng Generics – Learner

+0

OK, dễ hiểu! Tôi chỉ nghĩ rằng nếu bạn chỉ là một giải pháp làm việc nhanh nhất có thể, tôi sẽ chỉ cho bạn một trong những khung công tác. – Kenneth

Trả lời

2

Something như thế này nên làm việc (gõ từ đầu tôi, vì vậy bạn sẽ cần phải kiểm tra các chi tiết cú pháp - nhưng sẽ cho bạn hướng - hoặc tôi sẽ thêm vào sau)

MethodInfo methodInfo = typeof(ServiceManager).GetMethod("GetService"); 
MethodInfo methodInfoGeneric = methodInfo.MakeGenericMethod(new[] { typeOfService }); 
methodInfoGeneric.Invoke(serviceManager, new object[] { }); 
+0

Vì vậy, cách phản chiếu ... thực sự tốt để biết chi tiết như vậy ...Cảm ơn bạn! – Learner

+0

bạn được chào đón Cristi - không có cách nào khác để 'di chuyển' từ 'Type' vào một thế giới 'đánh máy mạnh'. – NSGaga

+0

btw, tôi vẫn cần bằng cách nào đó một kết nối giữa IService và IService , nếu không nó không thể làm việc. IService của tôi trông như thế nào? – Learner

2

Để gọi một phương thức chung mà kiểu chỉ được biết trong thời gian chạy đòi hỏi phải sử dụng sự phản chiếu. Ví dụ: trong mẫu mã cuối cùng của bạn, bạn ngụ ý rằng bạn không thể gọi GetService<BookService>, nhưng bạn vẫn đang thêm new Book() vào dịch vụ. Bạn cũng sẽ phải sử dụng sự phản chiếu để khởi tạo đối tượng mới, bởi vì, một lần nữa, bạn không biết loại lúc biên dịch. Vì vậy, bạn sẽ cần phải sử dụng phản chiếu ít nhất ba lần: Một lần để gọi phương thức trả về dịch vụ, một lần để tạo đối tượng mới và một lần để gọi phương thức chèn trên dịch vụ.

Bạn có thể cách ly một số độ phức tạp này với dependency injectioninversion of control. Ví dụ: tạo một phương pháp chung như sau:

void CreateNewObject<T>() where T : new() 
{ 
    var service = GetServiceFor<T>(); 
    service.Repository.Insert(new T()); 
} 

Bây giờ, bạn chỉ cần sử dụng phản chiếu một lần, để gọi phương thức đó, thay vì ba lần.

+0

Điểm rất hay và thú vị! Có, xin lỗi về "Sách mới") (sao chép-dán) ... và tôi đoán phần phản chiếu tôi có thể lấy nó từ 'NSGaga' – Learner