雖然我一直在使用Ninject,但我一般都很喜歡DI,所以我是使用Simple Injector的全新品牌。吸引我想要使用Simple Injector的一件事是裝飾者的易用性。如何裝飾依賴運行時值創建的類
我已經能夠在所有正常情況下使用Simple Injector成功使用裝飾器,在請求服務時解決了依賴關係。然而,我很難弄清楚在服務必須使用運行時值構建的情況下是否有辦法讓我的裝飾器應用於案例中。
在Ninject中,我可以將ConstructorArgument
傳遞給kernel.Get<IService>
請求,該請求可以沿着N個裝飾器鏈一路繼承到「真正的」實現類。我無法想出一個方法來複制使用簡單注射器。
我已經在下面說明了一些非常基本的代碼。我想在現實世界中做的事情是將IMyClassFactory
實例傳遞給我的應用程序中的其他類。那些其他類可以使用它們創建IMyClass
實例,使用它們提供的IRuntimeValue
。他們從IMyClassFactory
得到的IMyClass
實例將被註冊的裝飾器自動裝飾。
我知道我可以在我的IMyClassFactory
或任何Func<IMyClass>
中手動應用我的裝飾器,但我希望它能「正常工作」。
我一直在試圖抽象出MyClass
構造,但我無法弄清楚如何使用IRuntimeValue
構造函數參數來解決它並進行裝飾。
我忽略了一個明顯的解決方案嗎?
using System;
using SimpleInjector;
using SimpleInjector.Extensions;
public class MyApp
{
[STAThread]
public static void Main()
{
var container = new Container();
container.Register<IMyClassFactory, MyClassFactory>();
container.RegisterDecorator(typeof (IMyClass), typeof (MyClassDecorator));
container.Register<Func<IRuntimeValue, IMyClass>>(
() => r => container.GetInstance<IMyClassFactory>().Create(r));
container.Register<IMyClass>(() => ?????)); // Don't know what to do
container.GetInstance<IMyClass>(); // Expect to get decorated class
}
}
public interface IRuntimeValue
{
}
public interface IMyClass
{
IRuntimeValue RuntimeValue { get; }
}
public interface IMyClassFactory
{
IMyClass Create(IRuntimeValue runtimeValue);
}
public class MyClassFactory : IMyClassFactory
{
public IMyClass Create(IRuntimeValue runtimeValue)
{
return new MyClass(runtimeValue);
}
}
public class MyClass : IMyClass
{
private readonly IRuntimeValue _runtimeValue;
public MyClass(IRuntimeValue runtimeValue)
{
_runtimeValue = runtimeValue;
}
public IRuntimeValue RuntimeValue
{
get
{
return _runtimeValue;
}
}
}
public class MyClassDecorator : IMyClass
{
private readonly IMyClass _inner;
public MyClassDecorator(IMyClass inner)
{
_inner = inner;
}
public IRuntimeValue RuntimeValue
{
get
{
return _inner.RuntimeValue;
}
}
}
編輯1:
好,感謝史蒂芬爲偉大的答案。它給了我一些想法。
雖然不是我的情況,但更多的是「經典」。假設我有一個ICustomer
,它是在運行時通過讀取數據庫或從磁盤反序列化或創建的東西創建的。所以我想這將被認爲是一個「新」引用史蒂文連接articles之一。我想創建一個ICustomerViewModel
的實例,以便我可以顯示和操作我的ICustomer
。我的具體CustomerViewModel
類在其構造函數中接受了ICustomer
以及可以由容器解析的另一個依賴項。
所以我有一個ICustomerViewModelFactory
有一個.Create(ICustomer customer)
定義方法返回ICustomerViewModel
。我總能得到這個工作之前,我問這個問題,因爲我在執行的ICustomerViewModelFactory
我能做到這一點(廠組成根實現):
return new CustomerViewModel(customer, container.GetInstance<IDependency>());
我的問題是,我想我的ICustomerViewModel
由容器進行裝飾並且將它推到新的地位。現在我知道如何解決這個限制。
所以我想我的後續問題是:我的設計是否在第一個地方錯了?我真的覺得ICustomer
應該被傳遞到CustomerViewModel
的構造函數中,因爲它演示了它的意圖,它是必需的,得到驗證等。我不想在事後添加它。
此外,如果服務取決於運行時值,那麼您已經將一些知識用於服務的實現方面,這是您嘗試避免的一點。如果一個實現需要傳遞數字42,那麼這個數字是否與不同的實現有關? 42是什麼意思? –
@ LasseV.Karlsen我完全同意你的價值類型和類似的東西。但我試圖讓我的腦袋裏說,運行時的價值是ICustomer剛剛從數據庫中讀入,我需要將它(以及一些其他容器解析的依賴關係)傳遞給一個構造函數說一個CustomerViewModel。雖然史蒂文給了我很多想法,但是這是否是正確的設計。 –
這是我消化和思考的很多信息(並且感謝您的鏈接並幫助我陷入成功之坑)。我將添加一個編輯以作進一步評論。實際上我自己想出了你自己的第二個解決方案,但是有點害怕它,因爲1)我從來沒有使用ThreadLocal存儲(整潔),2)我擔心可能存在一些其他的副作用,在上下文中引用對象。但那可能是我走的路。 –