仅使用基类的依赖注入示例

时间:2009-09-03 14:25:30

标签: .net design-patterns dependency-injection inversion-of-control methodology

是否可以在没有任何第三方工具的情况下进行DI?在他们发现一些DI框架之前,我已经读过人们用抽象类和接口来做这件事。如何以这种非常基本的形式完成ID?

5 个答案:

答案 0 :(得分:4)

在实例化它时,只需将依赖项传递给类的构造函数即可。当项目很小(低于几千行代码)时,不需要DI框架 - 您可以编写工厂并手动连接所有依赖项。

答案 1 :(得分:2)

this tutorial中有一个很好的描述。

基本上,您所做的就是让DependingClass只了解Interface,然后使用IndependentClass实现该界面。使用构造函数重载,您可以让单元测试框架在模拟对象中发送 有些代码可能会让我更容易理解我的目标:

public interface IAnInterface
{
    void MethodOne();
    void MethodTwo();
}

public class IndependentClass : IAnInterface
{
     // Implements all members of IAnInterface
}

public class DependentClass
{
    private IAnInterface _dependency;

    public DependentClass() : this(new IndependentClass()) { }

    public DependentClass(IAnInterface dependency)
    {
        this._dependency = dependency;
    }
}

现在,如您所见,我们提供了一个默认的类类型,如果没有为构造函数提供参数,则会对其进行实例化。但是我们也允许实现相同接口的不同类的 injection ,或者同样的模拟对象。

编辑:正如评论中所指出的,在较大的应用程序中,拥有一个实例化DependingClass的工厂并删除“默认”构造函数可能更好。这样,如果您决定更改实施,则只需在一个地方进行更改。

答案 2 :(得分:2)

当然,没有第三方工具也是可能的。简单样本:

interface ILogger
{
    void Log(string text);
}

class SomeClass
{
    private ILogger _logger;
    public SomeClass(ILogger logger)
    {
        _logger = logger;
    }

    public void DoSomeWork()
    {
        Log("Starting");
        // do work

        Log("Done");
    }

    private void Log(string text)
    {
        if (_logger != null)
        {
            _logger.Log(text);
        }
    }
}

SomeClass在构造函数中输入ILogger。它用它来记录一些输出。假设我们想在控制台中使用它:

class ConsoleLogger : ILogger
{
    public void Log(string text)
    {
        Console.WriteLine(text);
    }
}

在某些代码中:

SomeClass instance = new SomeClass(new ConsoleLogger());
instance.DoSomeWork();

..但是我们希望将日志改为文件:

class FileLogger : ILogger
{
    private string _fileName;
    public FileLogger(string fileName)
    {
        _fileName = fileName;
    }

    public void Log(string text)
    {
        File.AppendAllText(_fileName, text);
    }
}

因此,我们注入文件记录器:

SomeClass instance = new SomeClass(new FileLogger("path to file"));
instance.DoSomeWork();

SomeClass很高兴不知道正在使用的ILogger实现,只是使用注入的任何实现。通常一个工厂创建接口实现的实例而不是在整个代码中构造对象通常是一个好主意,以便更改使用中的实现更简单。

答案 3 :(得分:0)

您可以创建通过接口相互通信的组件,并让您的托管程序实例化组件并将它们链接在一起。

这将是您的解决方案结构:

  • 定义组件之间契约的dll程序集(接口+作为接口方法签名一部分的数据对象)。

  • 一个或多个定义组件(实现接口)的dll程序集。组件之间的任何通信都是通过接口完成的。

  • 启动托管进程的exe程序集,实例化组件并链接它们设置一些属性。每当您需要替换一个组件时,您只需要更改此项目。

您可以为任何组件创建单元测试,模拟您正在测试的组件使用的组件。

您还可以从托管项目中的app.confing文件中读取属性绑定。

答案 4 :(得分:0)

有三种方法可以做到......

  1. 将引用传递给构造函数中的依赖实例(它是实现接口的类的实例)。

    public class MyClass
    {
        private readonly ISpillDAL iSpDal;
        public ISpillDAL SpillDal { get { return iSpDal; } }
        public SpillLogic() : this(null) { }
        public SpillLogic(ISpillDAL splDAL)
        {
           iSpDal = splDAL ?? new SpillDAL();  // this allows a default 
        }
    }
    
  2. 创建新对象,然后通过属性设置器

    传递对依赖对象的引用
    public class MyClass 
    { 
       private readonly ISpillDAL iSpDal; 
       public ISpillDAL SpillDal    
       { 
          set { iSpDal = value; } 
          get { return iSpDal; } 
       }
       public SpillLogic() { }        
    }
    
  3. 在接受引用的对象中使用函数,并将其分配给您为此创建的内部provbate变量

    public class MyClass 
    { 
       private readonly ISpillDAL iSpDal; 
       public ISpillDAL SpillDal    
       { 
          set { iSpDal = value; } 
          get { return iSpDal; } 
       }
       public SpillLogic() { }    
       public void InjectSpillDAL(  ISpillDAL splDAL )
       {  iSpDal = splDAL; } 
    }