【问题标题】:How to initialize services in a chain constructor aproach如何在链构造方法中初始化服务
【发布时间】:2022-11-12 14:52:18
【问题描述】:

我有以下 Main 类,它将 dataStore 作为 Foo 类的构造函数参数。

在 Main 类中,我只想将一个构造函数“dataStore”传递给 Foo,但在 Foo 构造函数类中,除了 dataStore 之外,我还想初始化一些其他服务。

public class Main
{
    private DataStore dataStore = new DataStore();

    public Main()
    {
        var foo = new Foo(dataStore);
        foo.DoSomething();
    }
}

我已经尝试使用链接 Foo 构造函数的这种方法,但只有 dataStore 被初始化, 在这种情况下,_serviceOne 和 _serviceTwo 为 null(因为我在构造函数链接中传递了 null,而第二个构造函数从未被调用)。

public class Foo
{
    private readonly DataStore _dataStore;
    private readonly IServiceOne _serviceOne;
    private readonly IServiceTwo _serviceTwo;


    public Foo(DataStore dataStore) : this(null, null)
    {
        _dataStore = dataStore;
    }

    public Foo(IServiceOne serviceOne, IServiceTwo serviceTwo)
    {
        _serviceOne = serviceOne;
        _serviceTwo = serviceTwo;
    }

    public void DoSomething()
    {
        // do something
    }
}

如果我尝试将所有数据仅传递给一个 Foo 构造函数,我需要在 Main 类中传递 _dataStore 、 _serviceOne 和 _serviceTwo 作为 Foo 的参数,而我不这样做。

    public Foo(DataStore dataStore, IServiceOne serviceOne, IServiceTwo serviceTwo)
    {
        _dataStore = dataStore;
        _serviceOne = serviceOne;
        _serviceTwo = serviceTwo;
    }

有没有办法在 Main 类中只传递 dataStore 作为参数,并在 Foo 构造函数类中初始化所有字段(_dataStore,_serviceOne,_serviceTwo)?

本质上,我只将 dataStore 传递给 Foo 并在 Foo 类本身中实例化其余服务:

var foo = new Foo(dataStore);

【问题讨论】:

  • 在任何情况下,这些 - _dataStore、_serviceOne 或 _serviceTwo - 应该为空吗?那会很奇怪。如果没有向构造函数传递任何内容,您是否打算让Foo 创建某个类的实例并将其分配给该字段?
  • 本质上,我只将数据传递给 Foo ``` var foo = new Foo(dataStore); ``` 并实例化 Foo 类本身中的其余服务
  • 在您开始输入之前 - 我建议您编辑问题,而不是将其放在评论中。最好不需要通读 cmets 就可以明确问题。

标签: c# class dependency-injection constructor chaining


【解决方案1】:

我不确定你为什么需要这样做。您可以在 Foo(DataStore) 构造函数中初始化 IServiceOne、IServiceTwo 引用。但是,如果您真的需要,它肯定有效,这是一个根据您的代码改编的工作 dotnetfiddle:

https://dotnetfiddle.net/2FDjix

using System;

public class DataStore {}

public interface IServiceOne {}
public interface IServiceTwo {}

public class ServiceOne : IServiceOne {}
public class ServiceTwo : IServiceTwo {}

public class Program
{
        private static DataStore dataStore = new DataStore();
 
        public static void Main()
        {
            var foo = new Foo(dataStore);
            foo.DoSomething();
       }
}

public class Foo
{
    private readonly DataStore _dataStore;
    private readonly IServiceOne _serviceOne;
    private readonly IServiceTwo _serviceTwo;


    public Foo(DataStore dataStore) : this(null, null)
    {
        Console.WriteLine("Foo 1st construcor");
        _dataStore = dataStore;
    }

    public Foo(IServiceOne serviceOne, IServiceTwo serviceTwo)
    {
        Console.WriteLine("Foo 2nd constructor");
        _serviceOne = serviceOne;
        _serviceTwo = serviceTwo;
    }

    public void DoSomething()
    {
        // do something
    }
}

输出:

Foo 第二个构造函数

Foo 第一个构造函数

【讨论】:

    【解决方案2】:

    如果意图是

    • 您将始终将DataStore 传递给构造函数,并且该类将使用它。
    • 您可能想也可能不想传递IServiceOne 或IServiceTwo。如果您不通过它们,它们的类将提供自己的实现

    ...有几种方法可以做到这一点。这是一个。

    public Foo(DataStore dataStore) : this(dataStore, null, null)
    {
    }
    
    public Foo(DataStore dataStore, IServiceOne serviceOne, IServiceTwo serviceTwo)
    {
        _dataStore = dataStore;
        _serviceOne = serviceOne ?? new SomeImplementationOne();
        _serviceTwo = serviceTwo ?? new SomeImplementationTwo();
    }
    

    您可能想知道 - 如果您可以调用第二个构造函数并为 serviceOne 和 serviceTwo 传递空值,为什么还要使用第一个构造函数?

    答案是你可以这样做。拥有两个构造函数只会让选择变得更加清晰。如果您只有第二个构造函数,那么有人可能不知道他们可以选择传递null 并让类提供自己的实现。

    即使这样,它也有点令人困惑,因为调用者可能并不明显,如果它们传递 null,则该类将用其他东西替换 null。

    这是另一种选择:

    public Foo(DataStore dataStore)
    {
        _dataStore = dataStore ?? throw new ArgumentNullException(nameof(dataStore));
        _serviceOne = new SomeImplementationOne();
        _serviceTwo = new SomeImplementationTwo();
    }
    
    public Foo(DataStore dataStore, IServiceOne serviceOne, IServiceTwo serviceTwo)
    {
        _dataStore = dataStore ?? throw new ArgumentNullException(nameof(dataStore));
        _serviceOne = serviceOne ?? throw new ArgumentNullException(nameof(serviceOne));
        _serviceTwo = serviceTwo ?? throw new ArgumentNullException(nameof(serviceTwo));
    }
    

    这使构造函数保持分离。一个使用 dataStore 参数并提供另外两个。第二个构造函数要求您传递所有三个。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-02
      • 2021-12-21
      相关资源
      最近更新 更多