2011-01-25 26 views
19

Tôi có giao diện (IRepository<T>) hiện đang được mở rộng cho từng kho lưu trữ cụ thể, ví dụ: IUserRepository : IRepository<User>.Tự động giải quyết giao diện <T> để triển khai <T> trong StructureMap (chỉ khác với kiểu chung T)

Mỗi giao diện này có các lớp bê tông tương ứng, ví dụ: UserRepository : Repository<User>, IUserRepository.

Các kho lưu trữ riêng lẻ này không thêm bất kỳ chức năng bổ sung nào, chúng là tất cả các giao diện/lớp trống được sử dụng đơn giản để truyền các generics xung quanh.

Tôi sử dụng StructureMap để giải quyết IUserRepository thành UserRepository bằng cách sử dụng Cơ quan đăng ký có máy quét lắp ráp và một số quy ước đặt tên.

Tôi muốn này để di chuyển đến một cách tình trạng tối ưu hóa hơn, nơi thay vì đi qua xung quanh trường hợp của IUserRepository và nhận được nó quyết tâm UserRepository, tôi có thể vượt qua xung quanh IRepository<User> và có nó quyết tâm Repository<User>.

Điều này sẽ loại bỏ sự cần thiết phải tạo thêm các giao diện và lớp trống này.

Tôi không thể tìm cách sử dụng cấu hình StructureMap để thiết lập ánh xạ chung này. Một cái gì đó như thế này:

For(typeof(IRepository<>).Use(typeof(Repository<>)).WithTheGenericTypeFromTheInterfaceSuppliedAsATypeParameter(); 

Sửa

Sau khi nhận được các cặp vợ chồng đầu tiên của câu trả lời, tôi muốn làm rõ điều này hơn một chút.

Tôi không muốn tạo các lớp riêng lẻ cho bit For của cấu hình. Tôi muốn có các lớp/giao diện sau trong mã của tôi:

  • IRepository<T> where T : Entity
  • Repository<T> : IRepository<T> where T : Entity
  • Person : Entity
  • Product : Entity
  • Order : Entity
  • Whatever : Entity

Và đã ánh xạ sau đạt được với ước:

IRepository<Person> => Repository<Person> 
IRepository<Product> => Repository<Product> 
IRepository<Order> => Repository<Order> 
IRepository<Whatever> => Repository<Whatever> 

Nhưng tôi không muốn có để tạo ra một bản đồ cho mỗi người, ala:

For<IRepository<Person>>().Use<Repository<Person>>(); 
For<IRepository<Product>>().Use<Repository<Product>>(); 
For<IRepository<Order>>().Use<Repository<Order>>(); 
For<IRepository<Whatever>>().Use<Repository<Whatever>>(); 

tôi muốn có một bản đồ duy nhất mà sẽ làm việc cho bất kỳ IRepository:

For<IRepository<>>().Use<Repository<>>().WithTheSameGenericType(); 

sau đó tôi sẽ sử dụng để bơm các kho vào các dịch vụ:

public MyService(IRepository<User> userRepository) 

Và hy vọng điều đó sẽ được giải quyết thành Repository<User> khi chạy.

+0

cấu hình mong muốn của bạn là đã thực (không cần WithTheGenericTypeFromTheInterfaceSuppliedAsATypeParameter). Bạn đã thử nó và nó không hoạt động? –

+0

Tôi phải đã làm sai - nó sẽ không biên dịch lúc đầu, vì vậy tôi nghĩ rằng tôi sử dụng phiên bản chung của phương pháp (mặc dù khi tôi viết câu hỏi tôi đã sử dụng không chung chung). Một trong những buổi sáng đó. –

Trả lời

23

Hóa ra không có phương pháp ưa thích để gọi điện thoại, hoặc không dây ưa thích để làm, bạn chỉ cần sử dụng ForUse (các phiên bản không chung chung):

public class DataRegistry : Registry 
{ 
    public DataRegistry() 
    { 
     For(typeof (IRepository<>)).Use(typeof(Repository<>)); 
    } 
} 

Khi tôi tiêm một IRepository<Person> nó đang được giải quyết như một không Repository<Person> w.

Tôi gặp phải lỗi 104 nói Repository không thể cắm được cho IRepository. Điều này là do Kho lưu trữ được đánh dấu là abstract. Làm cho nó không trừu tượng cố định lỗi đó và nó hoạt động như mong muốn.

+0

Thật tuyệt khi biết, sẽ tiết kiệm được rất nhiều cấu hình. – CRice

+0

Với thiết lập này, làm cách nào bạn thêm phương thức cụ thể để nói Kho lưu trữ tức là AllByLastName() ??? Hay bạn chỉ cần trả về IQueryable? – Paul

+0

Chỉ cần trả về IQueryable. Logic cụ thể của miền như AllByLastName nằm trong lớp dịch vụ của chúng tôi. Repo có được, xóa, truy vấn, upsert vv –

0

Hãy xem giao diện IRegistrationConvention.

public class DomainRegistry : Registry 
{ 
    public DomainRegistry() 
     : base() 
    { 
     Scan(y => 
     { 
      y.AssemblyContainingType<IRepository>(); 
      y.Assembly(Assembly.GetExecutingAssembly().FullName); 
      y.With(new RepositoryTypeScanner()); 
     }); 

đâu RepositoryTypeScanner:

public class RepositoryTypeScanner : IRegistrationConvention 
{ 
    public void Process(Type type, Registry registry) 
    { 
     ... 
+0

Cảm ơn - nhưng điều đó không thực sự giải quyết được vấn đề. Tôi đang sử dụng một loại máy quét đã có, và sử dụng quy ước đặt tên để dây lên bất kỳ loại cụ thể để giao diện tương ứng của nó. Tôi muốn loại bỏ tất cả các giao diện và các loại bê tông đó và có structuremap tự động chuyển tham số chung giữa 'IRepository ' và 'Repository '. –

1

Dưới đây là một ví dụ. Bản đồ cấu trúc sẽ cho phép bạn làm cả hai.

//IRepository 
For<IMemberRepository>().Add<MemberRepository>(); 

//IRepository<T> 
For<IRepository<Member>>().Add<MemberRepository>(); 

Sau đó, nó là hữu ích để hỏi cho các loại bằng cách chỉ cần biết loại generic trong thời gian chạy:

Type repositoryType = typeof(IRepository<>).MakeGenericType(modelType); 
IocResolve.Resolve(repositoryType); 
+0

Cảm ơn - Tôi nghĩ câu hỏi của tôi hơi không rõ ràng. Tôi sẽ cập nhật nó ngay. Tôi đang cố gắng để tìm một giải pháp để tôi không cần phải tạo một lớp 'MemberRepository', nhưng thay vì có' IRepository 'ánh xạ tới' Repository 'với một quy ước. –

+0

Có bao nhiêu dòng cấu hình riêng lẻ mà bạn định hình mà bạn sẽ lưu bằng cách này? Bạn có nhiều lớp học không? – CRice

+0

Các kho lưu trữ khác nhau? Vâng một vài. Nhưng đó không phải là việc tạo ra các lớp IXXXREpository và XXXRepository cá nhân, vì chúng rỗng và được sử dụng đơn giản cho độ phân giải kiểu chung.Thay vì phải tạo thực thể, tạo giao diện, tạo lớp, chỉnh sửa đăng ký và sau đó sử dụng giao diện mới, sẽ tốt hơn cho mọi người chỉ để tạo thực thể và sử dụng 'IRepository '. Rất ít công việc hơn. –

4

Tôi đề nghị bạn hãy xem phương pháp AddAllTypesOf. Tôi đã có một số mã tương tự và đạt được mục tiêu của tôi bằng cách sử dụng nó (và giữ tính năng đăng ký tự động làm việc).

Trong trường hợp của bạn, bạn nên chỉ cần thay đổi

For<IRepository<Person>>().Use<Repository<Person>>(); 
For<IRepository<Product>>().Use<Repository<Product>>(); 
For<IRepository<Order>>().Use<Repository<Order>>(); 
For<IRepository<Whatever>>().Use<Repository<Whatever>>(); 

để

AddAllTypesOf(typeof(IRepository<>)); 

Cuối cùng, container của bạn sẽ tương tự như:

return new Container(x => 
     { 
      x.Scan(y => 
      { 
       y.TheCallingAssembly(); 
       y.AddAllTypesOf(typeof(IRepository<>)); 
       y.WithDefaultConventions(); 
      }); 
     }); 
+0

Tyron, bạn giải quyết một vấn đề rất dài chạy trong thế giới của tôi. CẢM ƠN BẠN. –

+1

Chỉ cần lưu ý, có một số khoảnh khắc khi lớp chung phụ thuộc vào hai hoặc nhiều lớp (ví dụ như các Mappers). Trong trường hợp đó, chỉ cần sử dụng biểu mẫu: 'y.AddAllTypesOf (typeof (IMapper <,>));' – tyron

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