2009-12-25 32 views
33

Unity có thể tự động giải quyết IEnumerable<T> không?Giải quyết IEnumerable <T> với Unity

Hãy nói rằng tôi có một lớp với constructor này:

public CoalescingParserSelector(IEnumerable<IParserBuilder> parserBuilders) 

và tôi cấu hình trường IParserBuilder cá nhân trong container:

container.RegisterType<IParserSelector, CoalescingParserSelector>(); 
container.RegisterType<IParserBuilder, HelpParserBuilder>(); 
container.RegisterType<IParserBuilder, SomeOtherParserBuilder>(); 

tôi có thể làm công việc này mà không cần phải thực hiện một cài đặt tùy chỉnh của IEnumerable<IParserBuilder>?

var selector = container.Resolve<IParserSelector>(); 

Cho đến nay tôi chưa thể diễn đạt điều này theo cách đơn giản, nhưng tôi vẫn đang tăng cường Unity vì vậy tôi có thể đã bỏ lỡ điều gì đó.

Trả lời

58

Nó chỉ ra rằng đây thực sự là hết sức đơn giản để làm:

container.RegisterType<IEnumerable<IParserBuilder>, IParserBuilder[]>(); 

Unity natively hiểu mảng, vì vậy chúng ta chỉ cần để lập bản đồ đếm được tới một mảng của cùng loại.

+1

Giải pháp tuyệt vời! Điều này tốt hơn tất cả các tùy chọn khác. – Jehof

+0

Và để điền vào IEnumerable để xây dựng tiêm (mà tôi hy vọng để xem trong câu trả lời ở đây), xin vui lòng tham khảo câu hỏi sau đây. http://stackoverflow.com/questions/6304355/way-to-fill-collection-with-unity –

+0

Quá xấu, bạn cần thêm đăng ký mới cho từng loại. Nếu chỉ có một cái gì đó đơn giản như 'container.RegisterType (GetType (IEnumerable (Of)), GetType (Array (Of)))' – Kurren

6

Tôi tin rằng bạn sẽ cần phải sử dụng phương pháp ResolveAll và sử dụng một đối tượng rõ ràng InjectionConstructor, ví dụ:

container.RegisterType<IParserBuilder, HelpParserBuilder>(); 
container.RegisterType<IParserBuilder, SomeOtherParserBuilder>(); 

var injectedBuilders = new InjectionConstructor(container.ResolveAll<IParserBuilder>()); 
container.RegisterType<IParserSelector, CoalescingParserSelector>(injectedBuilders); 

Nói cách khác, tôi không nghĩ rằng Unity có thể tự động giải quyết tất cả các trường hợp của một nhập và biết sử dụng phép xây dựng trên một lớp có tham số IEnumerable mà không khai báo rõ ràng đối tượng InjectionConstructor tại Run Time.

Cấp cho tôi vẫn đang học Unity, nhưng đây là trải nghiệm của tôi (YMMV).

+0

+1 Không hoàn hảo, nhưng chắc chắn tốt hơn những gì ban đầu tôi có. –

+0

Vấn đề chính mà tôi có với giải pháp này là các cá thể được giải quyết trên chuỗi thiết lập container hợp nhất không tốt cho tôi, tôi cần một bộ mới các mục được tiêm mỗi độ phân giải. Nhưng cảm ơn vì đã giúp tôi đi đúng hướng. –

10

@Metro Smurf: câu trả lời của bạn giúp tôi đi đúng hướng: Unity không thể tự động giải quyết phụ thuộc IEnumerable<T>.

Tôi không thể biên dịch ví dụ của bạn vì phương pháp RegisterType không lấy tham số InjectionConstructor làm thông số.

Cũng lưu ý rằng phương pháp ResolveAll sẽ chỉ hoạt động nếu bạn đã đăng ký nhiều loại với các tên khác nhau và phương pháp này KHÔNG trả về cá thể cho đăng ký mặc định (chưa đặt tên). (Tôi hoàn toàn không đồng ý với hành vi này btw).

Đây là những gì làm việc cho tôi:

container.RegisterType<IParserBuilder, HelpParserBuilder>("HelpParserBuilder"); 
container.RegisterType<IParserBuilder, SomeOtherParserBuilder>("SomeOtherParserBuilder"); 
container.RegisterType<IParserSelector, CoalescingParserSelector>(); 

container.Configure<InjectedMembers>().ConfigureInjectionFor<CoalescingParserSelector>(new InjectionConstructor(container.ResolveAll<IParserBuilder>())); 

Để giải quyết một trường hợp duy nhất, bạn sẽ cũng cần phải thêm một đăng ký mặc định nếu không thì cuộc gọi đến Resolve<T>() sẽ thất bại.

Mã này làm cho việc đăng ký mặc định để cho phép độ phân giải duy nhất:

container.RegisterType<IParserBuilder, HelpParserBuilder>(); 
IParserBuilder builder = container.Resolve<IParserBuilder>() 
+0

+1 Điều đó hoạt động tốt, nhưng không tốt hơn cũng không tệ hơn câu trả lời khác. –

+1

@Mark: Nếu bạn đăng ký nhiều phiên bản, bạn sẽ phải cung cấp các tên cá thể khác nhau. – ram

3

Tính đến tháng 5 năm 2010, có sự hỗ trợ bản địa cho điều đó. Kiểm tra nó ra here.

+0

Trong khi nó là tốt đẹp mà độ phân giải của 'IEnumerable 'được hỗ trợ, constructor tiêm không được hỗ trợ được nêu ra. –

5

Các

container.RegisterType<IEnumerable<IParserBuilder>, IParserBuilder[]>(); 

Làm việc đối với tôi chỉ cần ghi nhớ rằng khi bạn đăng ký loại IParserBuilder với container của bạn một tên duy nhất là cần thiết nếu không nó sẽ luôn là một mảng trống. Vì vậy, sử dụng

container.RegisterType<IParserBuilder, RealParserBuilder>("UniqueName"); 
5

Nếu bạn muốn thường hỗ trợ IEnumerable, sau đó bạn có thể thêm dòng này:

_container.RegisterType(typeof(IEnumerable<>), new InjectionFactory((IUnityContainer container, Type type, string name) => container.ResolveAll(type.GetGenericArguments().Single()))); 

Ấy phiên bản generic của

container.RegisterType<IEnumerable<IParserBuilder>, IParserBuilder[]>(); 
+0

Tôi thích lớp lót đơn giản ở đây. Điều này rất hữu ích cho đến khi Unity thêm hỗ trợ gốc cho 'constructor injection 'IEnumerable '. –

4

Tôi đã làm điều này như vậy

 container.RegisterTypes(
      AllClasses.FromLoadedAssemblies(). 
       Where(type => typeof(IParserBuilder).IsAssignableFrom(type)), 
      WithMappings.FromAllInterfaces, 
      WithName.TypeName, 
      WithLifetime.Transient); 

     container.RegisterType<IEnumerable<IParserBuilder>, IParserBuilder[]>(); 

Đăng ký nào rs tất cả mọi thứ mà thực hiện IParserBuilder, vì vậy khi bạn thêm một cái mới, bạn không cần phải thêm bất kỳ mã nào khác cho nó xuất hiện trong danh sách các nhà xây dựng.

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