Design patterns 使用构造函数参数未知的Unity注入实例

Design patterns 使用构造函数参数未知的Unity注入实例,design-patterns,dependency-injection,unity-container,constructor-injection,Design Patterns,Dependency Injection,Unity Container,Constructor Injection,我有一个如下的界面 public interface IDataProvider { List<string> GetData(); } 公共接口IDataProvider { List GetData(); } 信息技术的实施 public class TextDataProvider: IDataProvider { public TexDataProvider(string source){...} public List<string>

我有一个如下的界面

public interface IDataProvider
{
     List<string> GetData();
}
公共接口IDataProvider
{
List GetData();
}
信息技术的实施

public class TextDataProvider: IDataProvider
{
    public TexDataProvider(string source){...}
    public List<string> GetData() {...}
}
公共类TextDataProvider:IDataProvider
{
公共数据提供程序(字符串源){…}
公共列表GetData(){…}
}
我的一项服务使用IDataProvider获取数据。通过使用替代实现更改Unity Register方法,可以注入不同的实现

但是,构造函数的源参数仅在调用GetData时已知。因此,当Unity注册IDataProvider的实现时,源参数未知

我知道一种方法是将源代码移动到GetData方法,另一种方法是创建一个抽象工厂,其CreateMethod接受源代码参数并将其传递给IDataProvider实现构造函数。然后我们可以注入工厂而不是IDataProvider实例


但是有没有更好的方法来解决这个问题呢?

这里的核心问题是您试图使用运行时数据构建组件。当让容器构建对象图(由包含应用程序行为的应用程序组件组成)时,这些对象图应该只包含编译时已知的信息,或者在应用程序运行期间固定的信息(例如配置值)。当混合运行时数据时,事情开始迅速崩溃,因为您的DI配置开始迅速变得复杂,您的设计开始恶化(例如,因为您将开始添加工厂抽象),并且验证对象图的正确性变得更加困难

相反,应该使用方法调用(和属性调用)通过(已经存在的)对象图发送运行时数据。不使用构造函数,因为构造函数是在对象构造期间使用的

因此,我想到了两个解决方案。要么更改
GetData
方法的约定,要么引入允许检索上下文信息的抽象

更改
GetData的契约基本上意味着将运行时值传递到
GetData`方法:

public interface IDataProvider
{
    List<string> GetData(string source);
}
这种抽象允许检索当前上下文的源(不管上下文是什么,但通常是一个请求,比如web请求)

您的
TextDataProvider
实现现在可以依赖于这个新的
isoourceontext
抽象:

public class TextDataProvider : IDataProvider
{
    public TexDataProvider(ISourceContext sourceContext){...}
    public List<string> GetData() {
        // Call CurrentSource 'at runtime'; never in the ctor.
        string source = this.sourceContext.CurrentSource;
        ...
    }
}
乍一看,这个解决方案看起来与使用工厂抽象相同,但有一些相当重要的区别

首先,只有
TextDataProvider
实现知道新的抽象,其中使用
IDataProviderFactory
我们将对
IDataProvider
的所有消费者施加额外的复杂性(额外的抽象),因为
IDataProvider
的所有消费者也需要使用
IDataProviderFactory


此外,使用工厂仍然会使组件的构造复杂化,因为工厂需要在组件的构造函数中使用运行时值,而该组件可能还需要其他(编译时)依赖项。这很难实现,会导致对象图的创建延迟,并使验证此图是否可以实际构建变得更加困难。这将迫使您在运行时运行调用此工厂的实际代码,以确定它是否有效,而不是在应用程序启动后直接知道这一点(快速失败)。

这里的核心问题是您试图使用运行时数据构建组件。当让容器构建对象图(由包含应用程序行为的应用程序组件组成)时,这些对象图应该只包含编译时已知的信息,或者在应用程序运行期间固定的信息(例如配置值)。当混合运行时数据时,事情开始迅速崩溃,因为您的DI配置开始迅速变得复杂,您的设计开始恶化(例如,因为您将开始添加工厂抽象),并且验证对象图的正确性变得更加困难

相反,应该使用方法调用(和属性调用)通过(已经存在的)对象图发送运行时数据。不使用构造函数,因为构造函数是在对象构造期间使用的

因此,我想到了两个解决方案。要么更改
GetData
方法的约定,要么引入允许检索上下文信息的抽象

更改
GetData的契约基本上意味着将运行时值传递到
GetData`方法:

public interface IDataProvider
{
    List<string> GetData(string source);
}
这种抽象允许检索当前上下文的源(不管上下文是什么,但通常是一个请求,比如web请求)

您的
TextDataProvider
实现现在可以依赖于这个新的
isoourceontext
抽象:

public class TextDataProvider : IDataProvider
{
    public TexDataProvider(ISourceContext sourceContext){...}
    public List<string> GetData() {
        // Call CurrentSource 'at runtime'; never in the ctor.
        string source = this.sourceContext.CurrentSource;
        ...
    }
}
乍一看,这个解决方案看起来与使用工厂抽象相同,但有一些相当重要的区别

首先,只有
TextDataProvider
实现知道新的抽象,其中使用
IDataProviderFactory
我们将对
IDataProvider
的所有消费者施加额外的复杂性(额外的抽象),因为
IDataProvider
的所有消费者也需要使用
IDataProviderFactory

此外,使用工厂仍然会使组件的构造复杂化,因为工厂需要在组件的构造函数中使用运行时值,而该组件可能还需要其他(编译时)依赖项。这是很难实现的,因为