ฉันสามารถส่งพารามิเตอร์ตัวสร้างไปยังเมธอด Unity's Resolve () ได้หรือไม่


92

ฉันใช้ Unity ของ Microsoft สำหรับการฉีดพึ่งพาและฉันต้องการทำสิ่งนี้:

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

RepositoryAและRepositoryBทั้งสองมีตัวสร้างที่รับIDataContextพารามิเตอร์และฉันต้องการให้ Unity เริ่มต้นที่เก็บด้วยบริบทที่ฉันส่งผ่าน โปรดทราบIDataContextว่าไม่ได้ลงทะเบียนกับ Unity (ฉันไม่ต้องการ 3 อินสแตนซ์IDataContext)

คำตอบ:


71

ณ วันนี้พวกเขาได้เพิ่มฟังก์ชันนี้:

มันลดลงล่าสุดที่นี่:

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

อภิปรายได้ที่นี่:

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

ตัวอย่าง:

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


6
ลิงค์unity.codeplex.com/SourceControl/changeset/view/33899ไม่ทำงาน
M.Kumaran

2
"คลาส 'Microsoft.Practices.Unity.ParameterOverrides' ไม่มีพารามิเตอร์ประเภท" ฉันใช้ Unity 3.5; รหัสนี้ใช้ได้เฉพาะกับ Unity เวอร์ชันเก่าหรือไม่
Thomas Levesque

มันใช้ได้กับฉัน หมายเหตุ: ชั้นเรียนของคุณต้องมีตัวสร้างพารามิเตอร์ที่มีพารามิเตอร์ "name" และพารามิเตอร์ "address" Foo(string name, int address) { ... }
อา

การใช้ Unity 2.1: container.Resolve<IFoo>(new ParameterOverrides { { "name", "bar" }, { "address", 42 } });
mrfelis

38

<2 เซ็นต์>

จะเกิดอะไรขึ้นหากคุณตัดสินใจใช้บริการอื่นที่ต้องการบริบทมากกว่าหรือน้อยกว่าในภายหลัง

ปัญหาเกี่ยวกับพารามิเตอร์ตัวสร้างและ IoC คือในที่สุดพารามิเตอร์จะเชื่อมโยงกับชนิดคอนกรีตที่ใช้ในทางตรงกันข้ามกับการเป็นส่วนหนึ่งของสัญญาที่อินเทอร์เฟซบริการกำหนด

ข้อเสนอแนะของฉันคือให้คุณแก้ไขบริบทด้วยและฉันเชื่อว่า Unity ควรมีวิธีที่คุณจะหลีกเลี่ยงการสร้าง 3 อินสแตนซ์หรือคุณควรพิจารณาบริการจากโรงงานที่มีวิธีให้คุณสร้างวัตถุ

ตัวอย่างเช่นจะเกิดอะไรขึ้นหากคุณตัดสินใจสร้างที่เก็บข้อมูลที่ไม่ได้อาศัยฐานข้อมูลแบบเดิมเลย แต่ใช้ไฟล์ XML เพื่อสร้างข้อมูลจำลองสำหรับการทดสอบแทน คุณจะป้อนเนื้อหา XML ให้กับตัวสร้างนั้นอย่างไร

IoC ขึ้นอยู่กับรหัสการแยกส่วนโดยการผูกประเภทและความหมายของอาร์กิวเมนต์เข้ากับประเภทคอนกรีตคุณยังไม่ได้ทำการแยกส่วนอย่างถูกต้อง แต่ก็ยังมีการพึ่งพา

"โค้ดนี้สามารถพูดคุยกับที่เก็บประเภทใดก็ได้ตราบใดที่ใช้อินเทอร์เฟซนี้ .... โอ้และใช้บริบทข้อมูล"

ตอนนี้ฉันรู้แล้วว่าคอนเทนเนอร์ IoC อื่น ๆ รองรับสิ่งนี้และฉันก็มีในเวอร์ชันแรกของฉันด้วยเช่นกัน แต่ในความคิดของฉันมันไม่ได้อยู่ในขั้นตอนการแก้ปัญหา

</ 2 เซ็นต์>


3
ฉันเห็นประเด็นของคุณและเห็นด้วยกับคุณอย่างไรก็ตามฉันยังต้องการให้อินสแตนซ์ของ RepositoryA และ RepositoryB มี IDataContext เดียวกันซึ่งต้องแตกต่างจาก RepositoryC โปรดทราบว่า IRepositoryA และ IRepositoryB มีคุณสมบัติสำหรับ IDataContext ฉันจะอัปเดตโค้ดตัวอย่างเล็กน้อย
NotDan

2
จุดที่ดี ฉันกำลังจะเพิ่มพารามิเตอร์สตริงให้กับคอนสตรัคเตอร์ แต่หลังจากดูจุดนี้ฉันตัดสินใจที่จะทำให้มันเป็นวัตถุเป่าเต็ม ณ จุดนี้ประกอบด้วยสตริงเท่านั้น แต่ฉันสามารถดูได้แล้วว่าจะเพิ่มคุณสมบัติที่เป็นประโยชน์ได้อย่างไร
Santosh Benjamin

9

ขอบคุณครับ ... ของผมคล้ายกับโพสต์ของ "Exist" ดูด้านล่าง:

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

        _activeDirectoryService = container.Resolve<IActiveDirectoryService>(new ResolverOverride[]
        {
            new ParameterOverride("activeDirectoryServer", "xyz.adserver.com")
        });

5

คุณสามารถใช้ InjectionConstructor / InjectionProperty / InjectionMethod ขึ้นอยู่กับสถาปัตยกรรมการฉีดของคุณภายใน ResolvedParameter <T> ("name") เพื่อรับอินสแตนซ์ของวัตถุที่ลงทะเบียนไว้ล่วงหน้าในคอนเทนเนอร์

ในกรณีของคุณออบเจ็กต์นี้ต้องลงทะเบียนด้วยชื่อและสำหรับอินสแตนซ์เดียวกันคุณต้องใช้ ContainerControlledLifeTimeManager () เป็น 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
คุณแน่ใจเกี่ยวกับรหัสนี้หรือไม่? ไม่ได้รวบรวม ... Resolveใช้การรวบรวมResolverOverrideและInjectionConstructorไม่ใช่ไฟล์ResolverOverride.
Thomas Levesque

ใช่มันดูผิด แม้ว่าความสามัคคีควรได้รับการออกแบบมาอย่างนั้น หากชื่อพารามิเตอร์เปลี่ยนทุกอย่างจะพัง
Frank Q.

3

คำตอบสั้น ๆ คือ: ไม่ ขณะนี้ Unity ไม่มีวิธีที่จะส่งผ่านพารามิเตอร์ไปยังตัวสร้างที่ไม่คงที่หรือถูกฉีดเข้าไปที่ฉันสามารถหาได้ IMHO นั่นคือสิ่งเดียวที่ยิ่งใหญ่ที่สุดที่ขาดหายไป แต่ฉันคิดว่ามันเกิดจากการออกแบบมากกว่าการละเว้น

ดังที่ Jeff Fritz ตั้งข้อสังเกตในทางทฤษฎีคุณสามารถสร้างตัวจัดการอายุการใช้งานที่กำหนดเองซึ่งรู้ว่าบริบทใดที่จะแทรกเข้าไปในประเภทต่างๆ แต่นั่นเป็นระดับของการเข้ารหัสที่ยากซึ่งดูเหมือนว่าจะขัดขวางวัตถุประสงค์ของการใช้ Unity หรือ DI ในตอนแรก

คุณสามารถถอยกลับจาก DI เต็มรูปแบบและทำให้การใช้งานที่เก็บของคุณรับผิดชอบในการสร้างบริบทข้อมูลของตนเอง อินสแตนซ์บริบทยังคงสามารถแก้ไขได้จากคอนเทนเนอร์ แต่ตรรกะในการตัดสินใจว่าจะใช้อันใดจะต้องนำไปใช้กับที่เก็บ มันไม่บริสุทธิ์อย่างแน่นอน แต่มันจะกำจัดปัญหาได้


1

อีกทางเลือกหนึ่งที่คุณสามารถใช้ได้ (ไม่ทราบว่าเป็นแนวทางปฏิบัติที่ดีหรือไม่) คือการสร้างคอนเทนเนอร์สองคอนเทนเนอร์และลงทะเบียนอินสแตนซ์สำหรับแต่ละรายการ:

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

หวังว่านี่จะช่วยได้เช่นกัน


0

NotDan ฉันคิดว่าคุณอาจตอบคำถามของคุณเองในความคิดเห็นต่อ Lassevk

ขั้นแรกฉันจะใช้ LifetimeManager เพื่อจัดการวงจรชีวิตและจำนวนอินสแตนซ์ของ IDataContext ที่ Unity สร้างขึ้น
http://msdn.microsoft.com/en-us/library/cc440953.aspx

ดูเหมือนว่าContainerControlledLifetimeManagerวัตถุจะให้การจัดการอินสแตนซ์ที่คุณต้องการ ด้วย LifetimeManager นั้น Unity ควรเพิ่มอินสแตนซ์เดียวกันของ IDataContext ให้กับอ็อบเจ็กต์ทั้งหมดที่ต้องการการพึ่งพา IDataContext

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.