正如其他答案所述,依赖注入是在使用它的类之外创建依赖项的一种方式。您从外部注入它们,并从类内部控制它们的创建。这也是为什么依赖注入是控制反转(IoC)原则的实现。
IoC是原则,DI是模式。根据我的经验,您可能“需要多个记录器”的原因实际上从未得到满足,但实际的原因是,无论何时测试某个东西,您都确实需要它。一个例子:
我的特点:
当我看报价时,我想要标记我是自动看的,这样我就不会忘记这么做。
你可以这样测试:
[Test]
public void ShouldUpdateTimeStamp
{
// Arrange
var formdata = { . . . }
// System under Test
var weasel = new OfferWeasel();
// Act
var offer = weasel.Create(formdata)
// Assert
offer.LastUpdated.Should().Be(new DateTime(2013,01,13,13,01,0,0));
}
在OfferWeasel的某处,它像这样为你创建了一个offer对象:
public class OfferWeasel
{
public Offer Create(Formdata formdata)
{
var offer = new Offer();
offer.LastUpdated = DateTime.Now;
return offer;
}
}
这里的问题是,这个测试很可能总是失败,因为所设置的日期将不同于所断言的日期,即使您只输入DateTime。现在在测试代码中,它可能会关闭几毫秒,因此总是会失败。现在一个更好的解决方案是创建一个接口,允许你控制将设置的时间:
public interface IGotTheTime
{
DateTime Now {get;}
}
public class CannedTime : IGotTheTime
{
public DateTime Now {get; set;}
}
public class ActualTime : IGotTheTime
{
public DateTime Now {get { return DateTime.Now; }}
}
public class OfferWeasel
{
private readonly IGotTheTime _time;
public OfferWeasel(IGotTheTime time)
{
_time = time;
}
public Offer Create(Formdata formdata)
{
var offer = new Offer();
offer.LastUpdated = _time.Now;
return offer;
}
}
接口是抽象。一个是真实的东西,另一个可以让你在需要的时候假装。测试可以这样更改:
[Test]
public void ShouldUpdateTimeStamp
{
// Arrange
var date = new DateTime(2013, 01, 13, 13, 01, 0, 0);
var formdata = { . . . }
var time = new CannedTime { Now = date };
// System under test
var weasel= new OfferWeasel(time);
// Act
var offer = weasel.Create(formdata)
// Assert
offer.LastUpdated.Should().Be(date);
}
Like this, you applied the "inversion of control" principle, by injecting a dependency (getting the current time). The main reason to do this is for easier isolated unit testing, there are other ways of doing it. For example, an interface and a class here is unnecessary since in C# functions can be passed around as variables, so instead of an interface you could use a Func<DateTime> to achieve the same. Or, if you take a dynamic approach, you just pass any object that has the equivalent method (duck typing), and you don't need an interface at all.
您几乎不需要超过一个记录器。尽管如此,依赖注入对于静态类型的代码(如Java或c#)是必不可少的。
和…
还应该注意的是,如果对象的所有依赖项都可用,则对象只能在运行时正确地实现其目的,因此设置属性注入没有太大用处。在我看来,当调用构造函数时,所有的依赖关系都应该得到满足,所以构造函数注入是可以使用的。