仅具有基类的依赖注入示例

发布于 2024-08-03 23:13:38 字数 86 浏览 7 评论 0原文

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

Is it possible to do DI without any third party tools? I've read about people doing it with an abstract class and interface before they discovered some DI framework. How is ID done in that very basic form?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

北方的巷 2024-08-10 23:13:39

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

Just pass the dependencies to the constructor of the class when you instantiate it. No DI frameworks are needed when the project is small (below a couple of thousand lines of code) - you can write a factory and wire up all the dependencies manually.

海拔太高太耀眼 2024-08-10 23:13:39

当然,无需第三方工具也是可以的。简单示例:

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);
        }
    }
}

SomeClassILogger 作为构造函数中的输入。它用它来记录一些输出。假设我们希望它出现在控制台中:

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 正在使用实现,并且只使用注入的实现。通常最好让工厂创建接口实现的实例,而不是在整个代码中构造对象,以便更轻松地更改正在使用的实现。

Of course it's possible without third-party tools. Simple sample:

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 takes an ILogger as input in the constructor. It uses it for logging some output. Let's say we want it in the console:

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

In some code:

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

..but then we want the log in a file instead:

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

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

So, we inject the file logger instead:

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

SomeClass is happily unaware of the ILogger implementation in use, and just uses whichever implementation that is injected. It's usually a good idea to have a factory creating the instances of the interface implementations instead of having the objects constructed all over the code, in order to make it simpler to change the implementation in use.

夜司空 2024-08-10 23:13:39

本教程中有一个很好的描述。

基本上,您所做的就是让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;
    }
}

现在,如您所见,我们提供了一个默认的类类型,如果没有向构造函数提供参数,它将被实例化。但我们也允许注入实现相同接口的不同类,或者相同接口的模拟对象。

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

There is a nice description in this tutorial.

Basically what you do is that you let the DependingClass only know about an Interface, and then you implement that interface with your IndependentClass. With constructor overloads, you let for example a unit testing framework send in a mock object.
Some code might make it easier to understand what I'm getting at:

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;
    }
}

Now, as you see, we have provided a default class type that will be instantiated if no argument is provided to the constructor. But we have also allowed for injection of a different class that implements the same interface, or a mock object of the same.

EDIT: As pointed out in a comment, it is probably better in a larger app to have a factory that instantiates the DependingClass, and remove the "default" constructor. That way you only have to change in one place if you decide to change the implementation.

-黛色若梦 2024-08-10 23:13:39

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

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

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

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

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

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

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

You can create your components communicating with each other through interfaces and have your hosting program that instantiates the components and link them together.

This would be your solution structure:

  • An dll assembly that defines the contract between components (interfaces + data objects that are part of the interface methods signatures).

  • One ore more dll assemblies that defines your components (that implement interfaces). Any communication between components is done through interfaces.

  • An exe assembly that starts up the hosting process, instantiates the components and link them setting some properties. Whenever you need to substitute one component you only need to change this project.

You can create unit tests for any of your components mocking up the components that are used by the component you are testing.

Also you can get fancy reading the property bindings from the app.confing file in the hosting project.

べ繥欢鉨o。 2024-08-10 23:13:39

您可以通过三种方法来做到这一点...

  1. 在构造函数中传递对依赖实例(当然是实现接口的类的实例)的引用。

    公共类MyClass
    {
        私有只读 ISpilDAL iSpDal;
        公共 ISpilDAL SpillDal { 获取 { 返回 iSpDal; } }
        公共 SpillLogic() : this(null) { }
        公共 SpillLogic(ISPillDAL splDAL)
        {
           iSpDal = splDAL ??新的 SpillDAL(); // 这允许默认值 
        }
    }
    
  2. 创建新对象,然后通过属性设置器将引用传递给依赖对象

    公共类MyClass 
    { 
       私有只读 ISpilDAL iSpDal; 
       公共 ISpilDAL SpillDal    
       { 
          设置 { iSpDal = 值; } 
          获取 { 返回 iSpDal; } 
       }
       公共 SpillLogic() { }        
    }
    
  3. 在对象中使用接受引用并将其分配给您为此创建的内部provbate变量

    公共类MyClass 
    { 
       私有只读 ISpilDAL iSpDal; 
       公共 ISpilDAL SpillDal    
       { 
          设置 { iSpDal = 值; } 
          获取 { 返回 iSpDal; } 
       }
       公共 SpillLogic() { }    
       公共无效 InjectSpillDAL( ISpillDAL splDAL )
       { iSpDal = splDAL; } 
    }
    

There are three ways you can do it...

  1. Pass the reference to the dependant instance (which is an instance of a class that implements the interface of course) in the constructor.

    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. Create the new object and then pass the reference to the dependant object via a property setter

    public class MyClass 
    { 
       private readonly ISpillDAL iSpDal; 
       public ISpillDAL SpillDal    
       { 
          set { iSpDal = value; } 
          get { return iSpDal; } 
       }
       public SpillLogic() { }        
    }
    
  3. Use a function within the object that accepts the reference and assigns it to the internal provbate variable you have created for this

    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; } 
    }
    
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文