Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 瞬态对象中的依赖注入_C#_Unit Testing_Design Patterns_Factory_Factory Pattern - Fatal编程技术网

C# 瞬态对象中的依赖注入

C# 瞬态对象中的依赖注入,c#,unit-testing,design-patterns,factory,factory-pattern,C#,Unit Testing,Design Patterns,Factory,Factory Pattern,我想要一些关于如何通过依赖项注入构造一些对象的建议 我的大多数应用程序都是单例的,将单例作为彼此的依赖注入是非常简单的 然而,我有一种情况,我动态地生成一些依赖于几个单例的瞬态对象 以下是当前情况的一些C#伪代码: // random singletons public static class SingletonA {...} public static class SingletonB {...} public static class SingletonC {...} // random

我想要一些关于如何通过依赖项注入构造一些对象的建议

我的大多数应用程序都是单例的,将单例作为彼此的依赖注入是非常简单的

然而,我有一种情况,我动态地生成一些依赖于几个单例的瞬态对象

以下是当前情况的一些C#伪代码:

// random singletons
public static class SingletonA {...}
public static class SingletonB {...}
public static class SingletonC {...}

// random objects that all need to depend on some subset of the above singletons
public class BaseTask {...}
public class TaskA : BaseTask {...}
public class TaskB : BaseTask {...}
public class TaskC : BaseTask {...}

public class Scheduler {
    public Scheduler() {
    }

    public void Start() {
        // When these tasks are created is actually really dependent on business logic,
        // and each task executes a bunch of internal logic.
        // Each Task can create more children Task at arbitrary times too.
        ...
        var taskA = new TaskA();
        ...
        var taskB = new TaskB();
        ...
        var taskC = new TaskC();
        ...
}
所有
TaskA
TaskB
TaskC
。。。这将调用单例上的方法。此外,每个任务都可以构造新任务

如果使用依赖项注入,我可以执行以下操作:

public class Scheduler {
    private ISingletonA _singletonA;
    private ISingletonB _singletonB;
    ...

    public Scheduler(ISingletonA singletonA, ISingletonB singletonB, ...) {
        _singletonA = singletonA;
        _singletonB = singletonB;
        ...
    }

    public void Start() {
        ...
        var taskA = new TaskA(_singletonA, _singletonB, ...);
        ...
        var taskB = new TaskB(_singletonA, _singletonB, ...);
        ...
        var taskC = new TaskC(_singletonA, _singletonB, ...);
        ...
    }
}
这看起来一团糟,所以我想把所有的
TaskA
TaskB
TaskC
重构成一个公共类,并制作一个类似工厂的东西:

public class Scheduler {
    public TaskFactory _taskFactory

    public Scheduler(TaskFactory taskFactory) {
        _taskFactory = taskFactory;
    }

    public void Start() {
        ...
        var taskA = _taskFactory.NewTaskA(_taskFactory);
        ...
        var taskB = _taskFactory.NewTaskB(_taskFactory);
        ...
        var taskC = _taskFactory.NewTaskC(_taskFactory);
        ...
    }
}

还有更好的主意吗?如果不是,我认为这不是工厂模式。是否有更准确的名称?

我将定义一个工厂类,其唯一目的是构造
TaskX
对象,包括包含所有依赖项:

class MyTaskFactory : IMyTaskFactory
{
    private readonly ISingletonA _singletonA;
    private readonly ISingletonB _singletonB;

    public MyTaskFactory(ISingletonA singletonA, ISingletonB singletonB)
    {
        _singletonA = singletonA;
        _singletonB = singletonB;
    }

    public T Resolve<T>() where T : ITask
    {
        if (typeof(T) == typeof(TaskA)) return (T)(object)GetTaskA();
        if (typeof(T) == typeof(TaskB)) return (T)(object)GetTaskB();
        if (typeof(T) == typeof(TaskC)) return (T)(object)GetTaskC();

        throw new ArgumentException(string.Format("Type not supported: {0}", typeof(T).FullName));
    }

    protected TaskA GetTaskA()
    {
        return new TaskA(_singletonA);
    }

    protected TaskB GetTaskB()
    {
        return new TaskB(_singletonA, _singletonB);
    }

    protected TaskC GetTaskC()
    {
        return new TaskC(_singletonA, "Other runtime parameter");
    }
}

public class Scheduler
{
    protected readonly IMyTaskFactory _taskFactory;

    public Scheduler(IMyTaskFactory taskFactory)
    {
        _taskFactory = taskFactory;
    }

    public void Start()
    {
        var taskA = _taskFactory.Resolve<TaskA>();
        var taskB = _taskFactory.Resolve<TaskB>();
        var taskC = _taskFactory.Resolve<TaskC>();
    }
}
类MyTaskFactory:IMyTaskFactory
{
私有只读ISingletonA_singletonA;
私有只读ISingletonB _singletonB;
公共MyTaskFactory(Isingletna singletonA、ISingletonB singletonB)
{
_单音=单音;
_singletonB=singletonB;
}
public T Resolve(),其中T:ITask
{
if(typeof(T)==typeof(TaskA))返回(T)(object)GetTaskA();
if(typeof(T)==typeof(TaskB))返回(T)(object)GetTaskB();
if(typeof(T)==typeof(TaskC))返回(T)(object)GetTaskC();
抛出新的ArgumentException(string.Format(“不支持的类型:{0}”,typeof(T.FullName));
}
受保护的TaskA GetTaskA()
{
返回新任务a(_singletonA);
}
受保护的TaskB GetTaskB()
{
返回新的TaskB(_singletonA,_singletonB);
}
受保护的TaskC GetTaskC()
{
返回新的TaskC(_singletonA,“其他运行时参数”);
}
}
公共类调度程序
{
受保护的只读IMyTaskFactory\u taskFactory;
公共调度程序(IMyTaskFactory任务工厂)
{
_taskFactory=taskFactory;
}
公开作废开始()
{
var taskA=_taskFactory.Resolve();
var taskB=_taskFactory.Resolve();
var taskC=_taskFactory.Resolve();
}
}
然后将工厂添加到合成根目录中:

container.Register<IMyTaskFactory,MyTaskFactory>();
container.Register();
依赖关系将显示在需要它们的地方


单击查找包含可编译代码的小提琴。

如果我错了,请纠正我,但我认为您所做的与抽象工厂模式类似

我不确定您希望应用程序的可配置程度。我对您当前的结构提出的建议是,根据您展示的内容,创建一个应用程序文件,您可以在其中混合和匹配注入

{
“调度程序”:[
{
“id”:“A”,
“类型”:“…”,
“任务”:“tA,tB”
},
{
“id”:“B”,
“类型”:“…”,
“任务”:“tC”
}
],
“任务”:[
{
“id”:“tA”,
“类型”:“…”
},
{
“id”:“tB”,
“类型”:“…”
},
{
“id”:“tC”,
“类型”:“…”
}
]
}
基本思想是,您可以将“任务”分配给“调度器”


但是,为了实现这一点,您需要使用另一个IoC容器,例如Autofac,因为默认的ASP.NET Core DI容器使这一点在某种程度上不可能实现。

您将单例显示为静态类。这是故意的吗?是的,使用工厂模式是处理瞬态对象需要注入依赖项的情况的第一个也是最明显的选择。工厂负责实例化和填充构造函数参数,只需将自己注入的依赖项复制到构造函数参数中即可。只需确保为工厂提供一个接口,以便单元测试可以存根它即可。@Nkosi它们当前是静态类。当我引入依赖注入时,它们将不是静态类。@JohnWu我认为工厂通常有一个create方法来创建各种对象。在我的例子中,我的工厂接口将有3个以上的creates(基本上将所有构造函数整理成一个类)。那还算是“工厂”吗?不幸的是,我还需要将工厂作为依赖项传递给每个
任务
类。@JohnWu我说的是语义意义上的
工厂
。我的任务实例化实际上更复杂。每个任务都依赖于一组不同的单例以及原语(如字符串、int等),因此不同的构造函数非常不同,很难概括。在这种情况下,似乎最好只是“违反”传统的“工厂”模式,在工厂中有多种创建方法。这种风格有名字吗?请记住,单元测试人员将不得不模拟这种风格,而且他们编写单个模拟
Resolve
语句更容易。但你不必这样做,它就是一个工厂。我不知道它有什么特别的名字,当你对不同类型有不同的方法时。我同意你的观点,单元测试人员将不得不模拟它,但是考虑到构造函数参数的差异,似乎很难将它们塞进一个通用方法中。你建议如何做到这一点?我倾向于同意。如果逻辑不是泛型的,那么泛型方法就不合适。您可以使用不同的方法。如果您愿意,也可以使用一系列简单(尽管看起来很傻)的
if
语句来实现这两者(请参见我更新的示例)。谢谢。我