DI 使用动态构造函数注入
DI using dynamic constructor injection
我在使用带有构造函数属性的 DI 时遇到问题。我正在根据我的 IPDFBuilder
.
构建一个 PDFBuilder
public interface IPDFBuilder
{
string templatefilepath { get; }
string templatefilename { get; }
Dictionary<string, string> dict { get; }
void CreatePDF();
}
public class PDFBuilder : IPDFBuilder
{
public string templatefilename { get; private set; }
public string templatefilepath { get; private set; }
public Dictionary<string, string> dict { get; private set; }
public PDFBuilder(string templatefilename, string templatefilepath, Dictionary<string, string> dict)
{
this.templatefilename = templatefilename;
this.templatefilepath = templatefilepath;
this.dict = dict;
}
public void CreatePDF() {
//Do something
}
}
这个PDFBuilder
可以并且将会在多个控制器中使用,例如:
public class KeuringController : Controller
{
private IPDFBuilder _PDFBuilder;
public KeuringController(IPDFBuilder pdfBuilder)
{
_PDFBuilder = pdfBuilder;
}
//Action methods that use `PDFBuilder` below...
}
但是,我无法在启动 class(DI 注册已完成)中设置 PDFBuilder
的属性,因为不同的控制器将对 [= 的属性使用不同的值13=] class。一个简单的解决方案是只创建属性 public 的设置器,因此在操作方法中我可以设置值然后调用 CreatePDF()
。然而,这感觉不对。另一个简单的解决方案是删除 class 属性,并将 PDFBuilder
的 3 个属性作为方法属性传递给 CreatePDF
方法,如下所示:
public void CreatePDF(string templatefilename, string templatefilepath, Dictionary<string, string> dict) {
//Do something
}
但是现在假设我的 PDFBuilder
有 10 个方法都需要这 3 个属性。那么这不是正确的解决方案吗?
那么正确的解决方案是什么?我在不同的 classes/interfaces 实现中多次遇到这个问题,希望在这些情况下的设计方面得到一些帮助。
您正在将运行时数据注入组件的构造函数,即 bad thing。解决方案是将这些运行时值从构造函数中移出到 CreatePDF
方法中:
public interface IPDFBuilder
{
void CreatePDF(string templatefilepath, string templatefilename,
Dictionary<string, string> dict);
}
您可以子类化(或原型,取决于您的要求)不同种类的 PDFBuilder 并将它们注入相应的 类。
我不知道你使用的是什么 DI 框架,但我很确定有一个选项可以告诉框架你想在特定的 类.[=10 中注入什么样的依赖关系=]
编辑:请记住:此解决方案不适用于运行时已知的值。
有两种方法可以满足您的需求:
1) Create factory for builder.
2) Create configurator for builder.
当你创建工厂时,你基本上指定了对象的创建方式,因此可以自由地将你想要的一切设置到不同构建器的不同实现中:
public inteface IPDFBuilderFactory
{
IPDFBuilder Create();
}
您将需要传递所有依赖项 - 这是一个缺点。我个人不喜欢这种方法。
另一种方法是创建这样的配置:
public interface IPDFConfiguration
{
string templatefilename {get;}
string templatefilepath {get;}
Dictionary<string, string> dict {get;}
}
并将其作为参数传递给构造函数:
public PDFBuilder(IPDFConfiguration configuration)
{
...
}
如果您决定在一段时间内更改它们,它将为您在初始化构建器时提供更多的灵活性。您也可以自由地初始化此配置 - 常量、配置、数据库等。
其中一个缺点 - 随着时间的推移,您的配置可能会变得非常笨拙,如果不进行重构,它将成为其他人的黑洞,所以要小心。
选择最适合你的。
我在使用带有构造函数属性的 DI 时遇到问题。我正在根据我的 IPDFBuilder
.
PDFBuilder
public interface IPDFBuilder
{
string templatefilepath { get; }
string templatefilename { get; }
Dictionary<string, string> dict { get; }
void CreatePDF();
}
public class PDFBuilder : IPDFBuilder
{
public string templatefilename { get; private set; }
public string templatefilepath { get; private set; }
public Dictionary<string, string> dict { get; private set; }
public PDFBuilder(string templatefilename, string templatefilepath, Dictionary<string, string> dict)
{
this.templatefilename = templatefilename;
this.templatefilepath = templatefilepath;
this.dict = dict;
}
public void CreatePDF() {
//Do something
}
}
这个PDFBuilder
可以并且将会在多个控制器中使用,例如:
public class KeuringController : Controller
{
private IPDFBuilder _PDFBuilder;
public KeuringController(IPDFBuilder pdfBuilder)
{
_PDFBuilder = pdfBuilder;
}
//Action methods that use `PDFBuilder` below...
}
但是,我无法在启动 class(DI 注册已完成)中设置 PDFBuilder
的属性,因为不同的控制器将对 [= 的属性使用不同的值13=] class。一个简单的解决方案是只创建属性 public 的设置器,因此在操作方法中我可以设置值然后调用 CreatePDF()
。然而,这感觉不对。另一个简单的解决方案是删除 class 属性,并将 PDFBuilder
的 3 个属性作为方法属性传递给 CreatePDF
方法,如下所示:
public void CreatePDF(string templatefilename, string templatefilepath, Dictionary<string, string> dict) {
//Do something
}
但是现在假设我的 PDFBuilder
有 10 个方法都需要这 3 个属性。那么这不是正确的解决方案吗?
那么正确的解决方案是什么?我在不同的 classes/interfaces 实现中多次遇到这个问题,希望在这些情况下的设计方面得到一些帮助。
您正在将运行时数据注入组件的构造函数,即 bad thing。解决方案是将这些运行时值从构造函数中移出到 CreatePDF
方法中:
public interface IPDFBuilder
{
void CreatePDF(string templatefilepath, string templatefilename,
Dictionary<string, string> dict);
}
您可以子类化(或原型,取决于您的要求)不同种类的 PDFBuilder 并将它们注入相应的 类。
我不知道你使用的是什么 DI 框架,但我很确定有一个选项可以告诉框架你想在特定的 类.[=10 中注入什么样的依赖关系=]
编辑:请记住:此解决方案不适用于运行时已知的值。
有两种方法可以满足您的需求:
1) Create factory for builder.
2) Create configurator for builder.
当你创建工厂时,你基本上指定了对象的创建方式,因此可以自由地将你想要的一切设置到不同构建器的不同实现中:
public inteface IPDFBuilderFactory
{
IPDFBuilder Create();
}
您将需要传递所有依赖项 - 这是一个缺点。我个人不喜欢这种方法。
另一种方法是创建这样的配置:
public interface IPDFConfiguration
{
string templatefilename {get;}
string templatefilepath {get;}
Dictionary<string, string> dict {get;}
}
并将其作为参数传递给构造函数:
public PDFBuilder(IPDFConfiguration configuration)
{
...
}
如果您决定在一段时间内更改它们,它将为您在初始化构建器时提供更多的灵活性。您也可以自由地初始化此配置 - 常量、配置、数据库等。
其中一个缺点 - 随着时间的推移,您的配置可能会变得非常笨拙,如果不进行重构,它将成为其他人的黑洞,所以要小心。
选择最适合你的。