2014-12-19 17 views
7

Đối với các giao diện và lớp học sau đây, làm cách nào để sử dụng Unity Container để Fluently (lập trình) nối nó lên để FooController nhận được một thể hiện của ARepositoryBarController nhận một thể hiện của BRepository.Xây dựng nhiều công cụ trong Unity Container

public interface IRepository 
{ 
} 

public class ARepository : IRepository 
{ 
} 

public class BRepository : ARepository 
{ 
} 

public class FooController 
{ 
    public FooController(IService service, IRepository repository) 
    { 
    } 
} 

public class BarController 
{ 
    public BarController(IService service, IRepository repository) 
    { 
    } 
} 
+0

Câu hỏi dup trông khác nhau, nhưng câu trả lời là hoàn toàn giống nhau. – jgauffin

+0

Đây là một câu trả lời khác hoạt động: http://stackoverflow.com/questions/4989676/injecting-a-specific-instance-of-an-interface-using-autofac – jgauffin

Trả lời

1

Một khả năng là để đăng ký loại hình cụ thể để được giải quyết bởi UnityContainer khi giải quyết IRepository:

IUnityContainer container = new UnityContainer(); 
container.RegisterType<IRepository, BRepository>(new ContainerControlledLifetimeManager()); 

Sử dụng điều này phụ thuộc vào việc bạn cần kiểm soát tốt hơn hạt trên những loại được giải quyết trong những bối cảnh nhất định - nếu bạn làm như vậy, bạn có thể xem xét sử dụng phiên bản địa phương IUnityContainer và sử dụng RegisterInstance() thay thế:

//Assumes container is instantiated and already populated with other instances/type mappings. 
IUnityContainer childContainer = container.CreateChildContainer(); 
container.RegisterInstance<IRepository>(new BRepository(), new ContainerControlledLifetimeManager()); 
2

Bạn có thể đạt được điều này tại thời điểm đăng ký bằng cách yêu cầu mỗi đăng ký bộ điều khiển cách giải quyết các tham số hàm tạo của nó.

container.RegisterType<FooController>(new InjectionConstructor(
    new ResolvedParameter<IService>(), new ResolvedParameter<ARepository>()); 

container.RegisterType<BarController>(new InjectionConstructor(
    new ResolvedParameter<IService>(), new ResolvedParameter<BRepository>()); 
3

Tôi đặc biệt khuyên bạn không nên tạo một UnityContainer chuyên dụng/cục bộ/được tiêm cho từng loại như một trong các áp phích được đề xuất.

Điều này có thể được tiếp cận theo hai cách.

Một là xác định cụ thể việc giải quyết trong thời gian đăng ký là TylerOhlsen được đề xuất. Đây là một giải pháp tốt, tuy nhiên nếu bạn đăng ký sau cả ARepositoryBRepository như triển khai cho IRepository, bạn vẫn cần phải đối phó với thực tế bạn có hai implenetations cho cùng một giao diện, và nếu một lớp thứ ba sẽ một ngày nào đó yêu cầu thực hiện IRepository, mà không xác định cụ thể trong đăng ký, nó sẽ nhận được một trường hợp không thể đoán trước.

Tùy chọn thứ hai, an toàn hơn một chút, đang đăng ký nhà máy cho IRepository. Ví dụ đơn giản nhất sẽ được sử dụng một chuỗi như chìa khóa, như thế này:

// Create a resolver(abstract factory) for the IRepository interface type 
var resolver = myContainer.Resolve<Func<IRepository>>(); 

// ... other code here... 

// Register mappings for the IRepository interface to appropriate concrete types 
myContainer.RegisterType<IRepository, ARepository>("A"); 
myContainer.RegisterType<IRepository, BRepository>("B"); 

Sau đó, trong việc thực hiện FooController và BarController nhận nhà máy func bằng cách tiêm và chọn trường hợp đúng.

public class FooController 
{ 
    IRepository repository; 

    public FooController(IService service, Func<IRepository> repositoryFactory) 
    { 
     repository = repositoryFactory("A"); 
    } 
} 

Bạn có thể đọc thêm về vấn đề này ở đây: http://msdn.microsoft.com/en-us/library/ff660854%28v=pandp.20%29.aspx

2

Bạn có thể đăng ký các loại với một tên và sau đó sử dụng trong một thuộc tính Dependency của lớp đích:

// Register mappings for the IRepository interface to appropriate concrete types 
myContainer.RegisterType<IRepository, ARepository>("A"); 
myContainer.RegisterType<IRepository, BRepository>("B"); 

Sau đó, trong FooController và BarController, hãy khai báo triển khai nào bạn yêu cầu với thuộc tính Dependency:

public class FooController 
{ 
    public FooController(IService service, [Dependency("A")] IRepository repository) 
    { 
    } 
} 

public class BarController 
{ 
    public BarController(IService service, [Dependency("B")] IRepository repository) 
    { 
    } 
} 

Bạn có thể sử dụng một public const string trong ARepositoryBRepository hơn "A""B" trong cả RegisterTypeDependency.

+1

không đánh bại toàn bộ mục đích sử dụng tiêm phụ thuộc nếu chúng ta tuyên bố sự phụ thuộc vào lớp chứ không phải là một người xác nhận hay cái gì đó? – Ruchan

+1

Lớp này nói rằng nó cần một "hương vị" đặc biệt của IService nhưng loại IService thực tế được khởi tạo được giải quyết trong thời gian chạy và phụ thuộc vào cách các loại được đăng ký. – PeteB

0

JoefGoldstein cho tôi hầu hết mọi cách, nhưng tôi gặp phải một số lỗi khi thử điều đó.

Tôi phải đăng ký các lớp học của mình với một phụ thuộc có tên và sử dụng lớp InjectionFactory để giải quyết sự phụ thuộc.

// register interfaces to implementations with a named dependency 
myContainer.RegisterType<IRepository, ARepository>("A"); 
myContainer.RegisterType<IRepository, BRepository>("B"); 

// register Injection factory to resolve the dependency 
container.RegisterType<Func<string, IRepository>>(
      new InjectionFactory(c => 
      new Func<string, IRepository>(name => c.Resolve<IRepository>(name))) 
); 

Sau đó, trong điều khiển của tôi

public class FooController 
{ 
    IRepository repository; 

    public FooController(IService service, Func<string, IRepository> repositoryFactory) 
    { 
     repository = repositoryFactory("A"); 
    } 
} 
Các vấn đề liên quan