第二種方法
我有一個家庭的,提供一個可擴展的應用程序(即,不固定的)設置的,其可以通過各種插件中使用的變量。動態依賴注入
的例子是:
- 日誌事件源
- 計算的結果源
- 對系統資源的使用
- 源的服務表現指標源
- ...
插件可以使用任何組合的SE。
樣品插件可以是:
- 的定製錯誤記錄器,使用1
- 定製的統計模塊,使用2
- 使用3和4
我想達到的是
- presen t給出一組可用的插件列表(當沒有日誌事件源時,您不應該能夠選擇自定義錯誤記錄器)。
- 得到一個簡單而安全的方式來將變量傳遞給插件,以避免由於缺少變量而導致運行時錯誤。
獎勵將允許插件可選地要求變量,例如,一個插件,需要4.並且可選地使用3.如果可用(但也可用其他)。
第一種方法
我想實現某種形式的「動態依賴注入」的。 讓我用一個用例來解釋它。
我正在構建一組將用於一系列應用程序的庫。 每個應用程序都可以提供一組不同的變量,這些變量可用於某些需要這些變量的「處理程序」。 根據具體的可用變量,必須確定可用處理程序的數量,因爲只有在處理程序可以訪問所有必需的變量時才能使用處理程序。 此外我正在尋找一種方法來儘可能安全地進行調用。編譯時間可能不可能,但「檢查一次,之後再也不會失敗」就可以。
下面是第一個草圖。在這個階段一切仍然可以改變。
class DynamicDependencyInjectionTest
{
private ISomeAlwaysPresentClass a;
private ISomeOptionalClass optionA;
private ISomeOtherOptionalClass optionB;
private ISomeMultipleOption[] multi;
private IDependentFunction dependentFunction;
void InvokeDependency()
{
// the number of available dependencies varies.
// some could be guaranteed, others are optional, some maybe have several instances
var availableDependencies = new IDependencyBase[] {a, optionA, optionB}.Concat(multi).ToArray();
//var availableDependencies = new IDependencyBase[] { a };
//var availableDependencies = new IDependencyBase[] { a, optionA }.ToArray();
//var availableDependencies = new IDependencyBase[] { a, optionB }.ToArray();
//var availableDependencies = new IDependencyBase[] { a , multi.First() };
//ToDo
// this is what I want to do
// since we checked it before, this must always succeed
somehowInvoke(dependentFunction, availableDependencies);
}
void SetDependentFunction(IDependentFunction dependentFunction)
{
if (! WeCanUseThisDependentFunction(dependentFunction))
throw new ArgumentException();
this.dependentFunction = dependentFunction;
}
private bool WeCanUseThisDependentFunction(IDependentFunction dependentFunction)
{
//ToDo
//check if we can fulfill the requested dependencies
return true;
}
/// <summary>
/// Provide a list which can be used by the user (e.g. selected from a combobox)
/// </summary>
IDependentFunction[] AllDependentFunctionsAvailableForThisApplication()
{
IDependentFunction[] allDependentFunctions = GetAllDependentFunctionsViaReflection();
return allDependentFunctions.Where(WeCanUseThisDependentFunction).ToArray();
}
/// <summary>
/// Returns all possible candidates
/// </summary>
private IDependentFunction[] GetAllDependentFunctionsViaReflection()
{
var types = Assembly.GetEntryAssembly()
.GetTypes()
.Where(t => t.IsClass && typeof (IDependentFunction).IsAssignableFrom(t))
.ToArray();
var instances = types.Select(t => Activator.CreateInstance(t) as IDependentFunction).ToArray();
return instances;
}
private void somehowInvoke(IDependentFunction dependentFunction, IDependencyBase[] availableDependencies)
{
//ToDo
}
}
// the interfaces may of course by changed!
/// <summary>
/// Requires a default constructor
/// </summary>
interface IDependentFunction
{
void Invoke(ISomeAlwaysPresentClass a, IDependencyBase[] dependencies);
Type[] RequiredDependencies { get; }
}
interface IDependencyBase { }
interface ISomeAlwaysPresentClass : IDependencyBase { }
interface ISomeOptionalClass : IDependencyBase { }
interface ISomeOtherOptionalClass : IDependencyBase { }
interface ISomeMultipleOption : IDependencyBase { }
class BasicDependentFunction : IDependentFunction
{
public void Invoke(ISomeAlwaysPresentClass a, IDependencyBase[] dependencies)
{
;
}
public Type[] RequiredDependencies
{
get { return new[] {typeof(ISomeAlwaysPresentClass)}; }
}
}
class AdvancedDependentFunction : IDependentFunction
{
public void Invoke(ISomeAlwaysPresentClass a, IDependencyBase[] dependencies)
{
;
}
public Type[] RequiredDependencies
{
get { return new[] { typeof(ISomeAlwaysPresentClass), typeof(ISomeOptionalClass) }; }
}
}
class MaximalDependentFunction : IDependentFunction
{
public void Invoke(ISomeAlwaysPresentClass a, IDependencyBase[] dependencies)
{
;
}
public Type[] RequiredDependencies
{
// note the array in the type of ISomeMultipleOption[]
get { return new[] { typeof(ISomeAlwaysPresentClass), typeof(ISomeOptionalClass), typeof(ISomeOtherOptionalClass), typeof(ISomeMultipleOption[]) }; }
}
}
正如馬克的答案所暗示的,您應該尊重KISS原則,並且不要試圖用一些模糊的DI重新發明輪子。想想那些會讀你的代碼的人。即使你在幾個月內也會頭疼,以便首先了解你的意圖...... – Fab