Tôi có thể chuyển các tham số của phương thức khởi tạo cho phương thức Resolve () của Unity không?


91

Tôi đang sử dụng Microsoft's Unity để chèn phụ thuộc và tôi muốn làm điều gì đó như sau:

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);

RepositoryARepositoryBcả hai đều có một phương thức khởi tạo nhận IDataContexttham số và tôi muốn Unity khởi tạo kho lưu trữ với ngữ cảnh mà tôi truyền nó. Cũng lưu ý rằng IDataContextkhông được đăng ký với Unity (tôi không muốn 3 trường hợp của IDataContext).

Câu trả lời:


71

Kể từ hôm nay, họ đã thêm chức năng này:

Nó nằm trong đợt giảm mới nhất ở đâ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

Thí dụ:

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



2
"Lớp 'Microsoft.Practices.Unity.ParameterOverrides' không có tham số kiểu". Tôi đang sử dụng Unity 3.5; mã này chỉ hợp lệ cho phiên bản Unity cũ hơn không?
Thomas Levesque

Nó làm việc cho tôi. Lưu ý: Lớp của bạn phải có một phương thức khởi tạo tham số với tham số "name" và tham số "address". Foo(string name, int address) { ... }
adun

Sử dụng Unity 2.1: container.Resolve<IFoo>(new ParameterOverrides { { "name", "bar" }, { "address", 42 } });
mrfelis

38

<2 xu>

Điều gì sẽ xảy ra nếu sau này bạn quyết định sử dụng một dịch vụ khác yêu cầu nhiều hơn hoặc ít hơn chỉ là ngữ cảnh?

Vấn đề với các tham số của nhà xây dựng 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 ngược với việc trở thành 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 nên giải quyết ngữ cảnh và tôi tin rằng Unity nên có cách để bạn tránh tạo 3 trường hợp của nó, hoặc bạn nên xem xét một dịch vụ nhà máy có cách để bạn xây dựng đối tượng.

Ví dụ: điều gì sẽ xảy ra nếu sau này bạn quyết định xây dựng một kho lưu trữ hoàn toàn không dựa vào cơ sở dữ liệu truyền thống mà thay vào đó sử dụng tệp XML để tạo dữ liệu giả cho thử nghiệm? Bạn sẽ làm thế nào về việc cung cấp nội dung XML cho hàm tạo đó?

IoC dựa trên việc phân tách mã, bằng cách gắn kiểu và ngữ nghĩa của các đối số vào các kiểu cụ thể, bạn thực sự chưa thực hiện việc tách một cách chính xác, vẫn còn 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, miễn là nó triển khai giao diện này .... Ồ, và sử dụng ngữ cảnh dữ liệu".

Bây giờ, tôi biết rằng các vùng chứa IoC khác có hỗ trợ cho điều này và tôi cũng đã 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 giải quyết.

</ 2 xu>


3
Tôi thấy quan đ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 của RepositoryA và RepositoryB có cùng một IDataContext, cần phải khác với RepositoryC. Cũng lưu ý rằng IRepositoryA và IRepositoryB có 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 đã định thêm một tham số chuỗi vào hàm tạo, nhưng sau khi xem điểm này, tôi quyết định biến nó thành một đối tượng hoàn chỉnh. Nó chỉ bao gồm các chuỗi vào 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ó
Santosh Benjamin

9

Thanks guys ... của tôi 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")
        });

5

Bạn có thể sử dụng InjectionConstructor / InjectionProperty / InjectionMethod tùy thuộc vào Kiến trúc Injection của bạn trong ResolvedParameter <T> ("name") để lấy một phiên bản của Đối tượng đã đăng ký trước trong vùng chứa.

Trong trường hợp của bạn, Đối tượng này phải được đăng ký với một Tên và đối với cùng một nội dung, 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? Nó không biên dịch ... Resolvecó một bộ sưu tập ResolverOverride, và InjectionConstructorkhông phải là một ResolverOverride.
Thomas Levesque

Yup Nó có vẻ sai. Mặc dù sự thống nhất nên thiết kế nó theo cách đó. Nếu tên thông số thay đổi thì mọi thứ sẽ bị hỏng
Frank Q.

3

Câu trả lời rất ngắn gọn là: không. Unity hiện không có cách nào để truyền các tham số vào phương thức khởi tạo không phải là hằng số hoặc được đưa vào mà tôi có thể tìm thấy. IMHO đó là điều lớn nhất mà nó thiếu, nhưng tôi nghĩ đó là do thiết kế chứ không phải do thiếu sót.

Như Jeff Fritz lưu ý, về lý thuyết, bạn có thể tạo một trình quản lý trọn đời tùy chỉnh biết trường hợp ngữ cảnh nào để đưa vào các loại khác nhau, nhưng đó là một cấp độ mã hóa cứng dường như làm mất đi mục đích của việc sử dụng Unity hoặc DI ngay từ đầu.

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


1

Một phương pháp thay thế khác mà bạn có thể sử dụng (không thực sự biết đó có phải là một phương pháp hay hay không) là tạo hai vùng chứa và đăng ký một phiên bản 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 cũng giúp


0

NotDan, tôi nghĩ rằng bạn có thể đã trả lời câu hỏi của riêng bạn trong phần bình luận cho lassevk.

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

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.