78

Tôi đang sử dụng Unity của Microsoft cho dependency injection và tôi muốn làm một cái gì đó như thế này:Tôi có thể chuyển các tham số hàm tạo cho phương thức Resolve() của Unity không?

IDataContext context = _unityContainer.Resolve<IDataContext>(); 
var repositoryA = _unityContainer.Resolve<IRepositoryA>(context); //Same instance of context 
var repositoryB = _unityContainer.Resolve<IRepositoryB>(context); //Same instance of context 

IDataContext context2 = _unityContainer.Resolve<IDataContext>(); //New instance 
var repositoryA2 = _unityContainer.Resolve<IRepositoryA>(context2); 

RepositoryARepositoryB cả hai đều có một constructor mà phải mất một tham số IDataContext, và tôi muốn Unity để khởi tạo kho lưu trữ với bối cảnh tôi vượt qua nó. Cũng lưu ý rằng IDataContext không được đăng ký với Unity (Tôi không muốn 3 phiên bản IDataContext).

Trả lời

62

Tính đến hôm nay họ đã thêm chức năng này:

Đó là trong sự sụt giảm mới nhất tại đây:

http://unity.codeplex.com/SourceControl/changeset/view/33899

Thảo luận về nó ở đây:

http://unity.codeplex.com/Thread/View.aspx?ThreadId=66434

Ví dụ:

container.Resolve<IFoo>(new ParameterOverrides<Foo> { { "name", "bar" }, { "address", 42 } });" 
+0

Xem thêm http://stackoverflow.com/questions/2813322/unity-2-0-how-to-use -resolve-with-resolveroverride –

+5

liên kết http://unity.codeplex.com/SourceControl/changeset/view/33899 không hoạt động –

+2

"Lớp 'Microsoft.Practices.Unity.ParameterOverrides' không có thông số loại". Tôi đang sử dụng Unity 3.5; mã này chỉ hợp lệ cho phiên bản cũ của Unity? –

33

< 2 cent>

gì nếu bạn sau này quyết định sử dụng một dịch vụ khác nhau mà đòi hỏi nhiều hơn hoặc ít hơn chỉ là bối cảnh?

Vấn đề với tham số hàm tạo và IoC là các tham số cuối cùng được gắn với loại bê tông đang được sử dụng, trái với việc là một phần của hợp đồng mà giao diện dịch vụ xác định.

Đề xuất của tôi là bạn cũng sẽ giải quyết ngữ cảnh và tôi tin rằng Unity nên có cách để bạn tránh xây dựng 3 trường hợp, hoặc bạn nên xem xét dịch vụ nhà máy có cách để bạn xây dựng đối tượng. Ví dụ, nếu sau này bạn quyết định xây dựng một kho lưu trữ không dựa vào cơ sở dữ liệu truyền thống, nhưng thay vì sử dụng một tệp XML để tạo ra dữ liệu giả cho thử nghiệm thì sao? Làm thế nào bạn sẽ đi về cho ăn nội dung XML để xây dựng mà? Io2 được dựa trên mã tách, bằng cách buộc trong các loại và ngữ nghĩa của các đối số cho các loại cụ thể, bạn thực sự đã không thực hiện việc tách một cách chính xác, vẫn còn một sự phụ thuộc.

"Mã này có thể nói chuyện với bất kỳ loại kho lưu trữ nào có thể, miễn là nó triển khai giao diện này .... Oh và sử dụng ngữ cảnh dữ liệu".

Bây giờ, tôi biết rằng các thùng chứa IoC khác có hỗ trợ cho điều này, và tôi đã có nó trong phiên bản đầu tiên của riêng mình, nhưng theo ý kiến ​​của tôi, nó không thuộc về bước phân giải.

</2 cent>

+3

Tôi thấy điểm của bạn và đồng ý với bạn, tuy nhiên tôi vẫn cần các phiên bản RepositoryA và RepositoryB để có cùng IDataContext, cần phải khác với RepositoryC. Cũng lưu ý rằng IRepositoryA và IRepositoryB có một thuộc tính cho IDataContext. Tôi sẽ cập nhật mã mẫu một chút. – NotDan

+2

Điểm tuyệt vời. Tôi đã được thêm một tham số chuỗi để constructor, nhưng sau khi xem điểm này, tôi quyết định làm cho nó một đối tượng thổi đầy đủ. Nó chỉ bao gồm các chuỗi tại thời điểm này, nhưng tôi đã có thể thấy làm thế nào tôi có thể thêm các thuộc tính hữu ích hơn cho nó –

0

NotDan, tôi nghĩ bạn có thể trả lời câu hỏi của riêng bạn trong các ý kiến ​​để lassevk.

Trước tiên, tôi sẽ sử dụng một LifetimeManager để quản lý vòng đời và số phiên bản của IDataContext mà Unity tạo ra.
http://msdn.microsoft.com/en-us/library/cc440953.aspx

Có vẻ như đối tượng ContainerControlledLifetimeManager sẽ cung cấp cho bạn quản lý mẫu mà bạn cần. Với LifetimeManager đó, Unity sẽ thêm cùng một thể hiện của IDataContext vào tất cả các đối tượng yêu cầu một sự phụ thuộc IDataContext.

3

Câu trả lời rất ngắn là: không. Unity hiện tại không có cách nào để truyền các tham số vào hàm tạo không liên tục hoặc được tiêm, mà tôi đã có thể tìm thấy. IMHO là điều lớn nhất duy nhất mà nó thiếu, nhưng tôi nghĩ nó là do thiết kế hơn là bỏ sót. Như Jeff Fritz lưu ý, bạn có thể tạo ra một người quản lý đời sống tùy chỉnh biết được bối cảnh nào để tiêm vào các loại khác nhau, nhưng đó là một mức độ mã hóa cứng dường như nhằm mục đích sử dụng Unity hoặc DI trong địa điểm đầu tiên.

Bạn có thể thực hiện một bước nhỏ trở lại từ DI đầy đủ và thực hiện triển khai kho lưu trữ của bạn chịu trách nhiệm thiết lập ngữ cảnh dữ liệu của riêng chúng. Các bối cảnh dụ vẫn có thể được giải quyết từ các container nhưng logic để quyết định cái nào để sử dụng sẽ phải đi vào việc thực hiện kho. Nó không phải là thuần khiết, chắc chắn, nhưng nó sẽ thoát khỏi vấn đề.

1

Một cách khác bạn có thể sử dụng (thực sự không biết nếu nó là một thực hành tốt hay không) đang tạo ra hai container và đăng ký một ví dụ cho mỗi:

IDataContext context = _unityContainer.Resolve<IDataContext>(); 
_unityContainer.RegisterInstance(context); 
var repositoryA = _unityContainer.Resolve<IRepositoryA>(); //Same instance of context 
var repositoryB = _unityContainer.Resolve<IRepositoryB>(); //Same instance of context 


//declare _unityContainer2 
IDataContext context2 = _unityContainer2.Resolve<IDataContext>(); //New instance 
_unityContainer2.RegisterInstance(context2); 
var repositoryA2 = _unityContainer2.Resolve<IRepositoryA>(context2); //will retrieve the other instance 

hy vọng điều này giúp quá

7

Bạn có thể sử dụng InjectionConstructor/InjectionProperty/InjectionMethod tùy thuộc vào kiến ​​trúc tiêm của bạn trong ResolvedParameter < T> ("tên") để có được một thể hiện của một đối tượng đăng ký trước trong container.

Trong trường hợp của bạn, đối tượng này phải được đăng ký với tên, và cho cùng một mức độ mà bạn cần ContainerControlledLifeTimeManager() làm LifeTimeManager.

_unityContainer.RegisterType<IDataContext,DataContextA>("DataContextA", new ContainerControlledLifeTimeManager()); 
_unityContainer.RegisterType<IDataContext,DataContextB>("DataContextB"); 

    var repositoryA = _unityContainer.Resolve<IRepositoryA>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextA"))); 

    var repositoryB = _unityContainer.Resolve<IRepositoryB>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextA"))); 

    var repositoryA2 = _unityContainer.Resolve<IRepositoryA>(new InjectionConstructor(
new ResolvedParameter<IDataContext>("DataContextB"))); 
+4

Bạn có chắc chắn về mã này không? Nó không biên dịch ... 'Resolve' lấy một tập hợp' ResolverOverride', và 'InjectionConstructor' không phải là' ResolverOverride'. –

+0

Có vẻ như sai. Mặc dù sự thống nhất nên đã thiết kế nó theo cách đó. Nếu tên tham số thay đổi mọi thứ bị hỏng –

5

Thanks guys ... mine tương tự như bài đăng của "Exist". Xem bên dưới:

 IUnityContainer container = new UnityContainer(); 
     container.LoadConfiguration(); 

     _activeDirectoryService = container.Resolve<IActiveDirectoryService>(new ResolverOverride[] 
     { 
      new ParameterOverride("activeDirectoryServer", "xyz.adserver.com") 
     }); 
Các vấn đề liên quan