将数据库初始化调用放在C#构造函数中可以吗?

时间:2020-03-06 14:59:58  来源:igfitidea点击:

我已经看到这是各种各样的代码库,并且想知道这是否普遍不被接受。

例如:

public class MyClass
{
   public int Id;

   public MyClass()
   {
      Id = new Database().GetIdFor(typeof(MyClass));
   }
}

解决方案

我可以用这种方法想到的唯一问题是,数据库初始化中的任何错误都将作为构造函数的异常传播。

好吧..我不会。但是话又说回来,我的方法通常涉及不负责检索其自身数据的类。

是的,我们可以这样做,但这不是最佳设计,而且构造函数中的错误处理不如其他地方那么整洁。

这也将使编写类的单元测试变得困难,因为我们将无法强制类使用db类的Mock / Stub版本。看这里:
http://en.wikipedia.org/wiki/Dependency_injection

如果引用数据库连接,则可以使用一次性模式:

public class MyClass : IDisposable
{
    private Database db;
    private int? _id;

    public MyClass()
    {
        db = new Database();
    }

    public int Id
    {
        get
        {
            if (_id == null) _id = db.GetIdFor(typeof(MyClass));
            return _id.Value;
        }
    }

    public void Dispose()
    {
        db.Close();
    }
}

用法:

using (var x = new MyClass()) 
{
    /* ... */

} //closes DB by calling IDisposable.Dispose() when going out of "using" scope

有几个原因通常不被认为是好的设计,其中一些原因已经引起了困难的单元测试和错误处理。

我选择不这样做的主要原因是,对象与数据访问层现在已经非常紧密地耦合在一起,这意味着在原始设计之外对该对象的任何使用都需要大量的返工。举个例子,如果遇到一个实例,在该实例中我们需要使用该对象而没有分配任何值来例如持久化该类的新实例?现在,我们或者必须重载构造函数,然后确保所有其他逻辑都能处理这种新情况,或者继承并重写。

如果对象和数据访问已分离,则可以创建一个实例,然后对其进行混合处理。或者,如果我们拥有使用相同实体但使用不同持久层的其他项目,则这些对象是可重用的。

话虽如此,我过去在项目中采取了更简单的耦合方式:)

为什么有人要使用模拟对象/存根而不是真实对象?
我们是否同意汽车制造商应使用纸板模型
进行碰撞测试?