2012-03-22 138 views
0

我认为,如果没有完整的体系结构更改,这可能是不可能的,但我有在运行时为用户公开可配置选项的类(插件)。在类实例化后的运行时使用依赖注入

该程序启动时,用户可以选择使用各种插件,用户面临的选项,他们可以修改为每个插件,用户按下播放按钮,这些配置选项读取和关闭我们去。

当用户选择要使用的插件时,将创建该类的实例,以便它可以显示该插件的可用选项。显然,在正常情况下,当类实例化时,构造函数参数被传入。在这种情况下,如果插件具有ILogger的构造函数参数,并且其具体类具有DirectoryPath的构造函数参数,但只有在用户单击播放后才可读取,我怎样才能获得我的国际奥委会容器通过它?

public class MyPlugin 
{ 
    private ILogger Logger; 
    private Dictionary<string, object> Properties = new Dictionary<string, object>(); 

    public MyPlugin(ILogger Logger) 
    { 
    this.Logger = Logger; 
    SetupProperties(); 
    } 

    private SetupProperties() 
    { 
    Properties.Add("LogDirectory","Please enter a directory"); 
    } 

    private void UserPressedPlay() 
    { 
    //We can now read the property values user has entered 
    //Now I want to instantiate FileLogger with the LogDirectory property 
    } 

    public DoSomething(string Data) 
    { 
    this.Logger.Write(Data); 
    } 
} 

public interface ILogger 
{ 
    void Write(string Data); 
} 

public FileLogger : ILogger 
{ 
    private string DirectoryPath; 

    public FileLogger(string Directory) 
    { 
    this.DirectoryPath = Directory; 
    } 

    public Write(string Data) 
    { 
     //Write to file 
    } 
} 
+3

我目前不使用IOC容器,因此我不会将其作为答案发布,但我认为您想要做的是传入ILogger工厂而不是实际的ILogger。然后可以使用用户的参数从UsrePressedPlay调用工厂以创建实际的Logger实例。 – 2012-03-22 21:01:14

+0

在不改变当前体系结构的情况下,我会在IoC中设置默认构造器设置 - 将设置目录设置为AppData \ Local \ Temp文件夹,然后在用户单击播放后重新初始化Logger界面。 虽然这是相当讨厌的事情,并通过记录器工厂提及500 - 内部服务器错误是一个好主意。 – 2012-03-22 21:14:46

+0

@ 500-InternalServerError所以你主张在这种情况下不使用IOC? – Jon 2012-03-22 21:18:20

回答

0

你想要做什么是传递一个ILogger工厂,而不是实际的ILogger。然后可以从UserPressedPlay中调用该工厂的用户参数来创建实际的Logger实例。

0

你可以一个DirectoryPath属性添加到您的FileLogger后来intitialize它。

public FileLogger : ILogger 
{ 
    public string DirectoryPath { get; set; } 

    public Write(string Data) 
    { 
     if (DirectoryPath != null) { 
      // Write to file 
     } 
    } 
} 
+0

那么不要使用IOC来实例化类? – Jon 2012-03-22 21:44:11

+0

一些IOC容器允许您定义在实例化后必须运行的附加规则或代码。或者通过只读属性将插件中的记录器公开。无论如何,您需要引用记录器才能设置目录路径。如果你可以用IOC做到这一点,好的。 – 2012-03-22 22:08:05

+0

只读属性如何工作? – Jon 2012-03-22 22:09:45

0

您可以使用Expression.New来使用上述参数动态创建/调用您的构造函数。

Func<String, FileLogger> func = GetConsturctor<String, FileLogger>(); // Cache it somewhere. 

    FileLogger logger = func(@"C:\Loggerpath\"); // instantiate 

    static Func<TArg, TRes> GetConsturctor<TArg, TRes>() 
    { 
     Type resultType = typeof(TRes); 
     Type argType = typeof(TArg); 

     Type[] argumentArray = new Type[] { argType }; 
     ConstructorInfo constructor = resultType.GetConstructor(argumentArray); 

     ParameterExpression param = Expression.Parameter(argType); 
     Expression<Func<TArg, TRes>> result = Expression.Lambda<Func<TArg, TRes>>(
     Expression.New(constructor, param), param); 
     return result.Compile(); 
    } 
0

所以DI提供了很大的灵活性和较低的耦合度,但通常没有必要。对于这种特殊情况,担心如何添加它可能会过度。看起来你已经有了一个图形用户界面,它被配置为匹配你用来配置它的FileLogger类,所以也许这里的DI是矫枉过正的。你有今天插件使用的其他类型的​​吗?如果是这样,工厂选项可能是一个很好的选择。基于提到的GUI,我怀疑只有一种类型的记录器。在这种情况下,请不要在这里使用DI挂机。如果你想弄清楚如何测试MyPlugin课程,并且不知道如何在没有DI的情况下这样做,那么请告诉我,我会扩展这个答案以展示如何完成。

希望有帮助!

布兰登