Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/293.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在C中使用依赖项注入和继承# 介绍_C#_Inheritance_Dependency Injection_Solid Principles - Fatal编程技术网

C# 如何在C中使用依赖项注入和继承# 介绍

C# 如何在C中使用依赖项注入和继承# 介绍,c#,inheritance,dependency-injection,solid-principles,C#,Inheritance,Dependency Injection,Solid Principles,大家好,我目前正在C#开发一个持久性库。在该库中,我实现了存储库模式,在这里我面临一个实际问题。 以下是我当前实施的一个简化示例,重点是: 持久性库中包含的抽象存储库: // Abstract type public interface IRepository<T> { Add(T obj); } // Concete type public class UserRepository : IRepository<User> { public UserRe

大家好,我目前正在C#开发一个持久性库。在该库中,我实现了存储库模式,在这里我面临一个实际问题。 以下是我当前实施的一个简化示例,重点是:

持久性库中包含的抽象存储库:

// Abstract type
public interface IRepository<T>
{
    Add(T obj);
}

// Concete type
public class UserRepository : IRepository<User>
{
    public UserRepository(/* Specific dependencies */) {}

    Add(User obj) { /* [...] */ }
}

// Decorator
public class LoggingRepository<T> : IRepository<T>
{
    private readonly IRepository<T> _inner;

    public LoggingRepository<T>(IRepository<T> inner) => _inner = inner;

    Add(T obj) 
    {
        Console.Log($"Adding {obj}...");
        _inner.Add(obj);
        Console.Log($"{obj} addded.");
    }
}
// Done using the DI.
IRepositoty<User> repository = 
    // Add as many decorators as you want.
    new LoggingRepository<User>(
        new UserRepository(/* [...] */));

// And here is your add method wrapped with some logging :)
repository.Add(new User());
公共抽象类存储库
{
受保护的存储库(
服务伊瑟维西娅,
IServiceB服务(B)
{
/* ... */
}
}
由库用户创建的具体存储库:

// Abstract type
public interface IRepository<T>
{
    Add(T obj);
}

// Concete type
public class UserRepository : IRepository<User>
{
    public UserRepository(/* Specific dependencies */) {}

    Add(User obj) { /* [...] */ }
}

// Decorator
public class LoggingRepository<T> : IRepository<T>
{
    private readonly IRepository<T> _inner;

    public LoggingRepository<T>(IRepository<T> inner) => _inner = inner;

    Add(T obj) 
    {
        Console.Log($"Adding {obj}...");
        _inner.Add(obj);
        Console.Log($"{obj} addded.");
    }
}
// Done using the DI.
IRepositoty<User> repository = 
    // Add as many decorators as you want.
    new LoggingRepository<User>(
        new UserRepository(/* [...] */));

// And here is your add method wrapped with some logging :)
repository.Add(new User());
公共类FooRepository:存储库
{
受保护的FoodRepository(
服务伊瑟维西娅,
IServiceB服务b):
基地(服务A、服务B)
{
/* ... */
}
}
问题
好的,在当前代码中,派生类必须知道基类的每个依赖项,这些依赖项可以是确定的,但是如果我向基类添加一个依赖项呢?每个派生类都将中断,因为它们需要将新的依赖项传递给基类。。。因此,目前,我被限制从不更改基类构造函数,这是一个问题,因为我希望我的基类具有进化的可能性这个实现显然打破了开放/封闭原则,但我不知道如何在不打破坚实基础的情况下解决这个问题

要求
  • 该库应便于用户使用
  • 混凝土存储库应该能够通过DI构建
  • 应将一个或多个依赖项添加到抽象存储库中,而不影响派生存储库
  • 应该可以使用命名约定在DI容器中注册每个存储库,就像ASP.NET MVC框架与控制器一样
  • 如果用户愿意,应该能够在其派生存储库中添加更多依赖项
已经设想的解决办法 1.服务聚合器模式 接下来,可以在这种情况下应用服务聚合器模型,因此代码如下所示:

持久性库中包含的抽象存储库:

// Abstract type
public interface IRepository<T>
{
    Add(T obj);
}

// Concete type
public class UserRepository : IRepository<User>
{
    public UserRepository(/* Specific dependencies */) {}

    Add(User obj) { /* [...] */ }
}

// Decorator
public class LoggingRepository<T> : IRepository<T>
{
    private readonly IRepository<T> _inner;

    public LoggingRepository<T>(IRepository<T> inner) => _inner = inner;

    Add(T obj) 
    {
        Console.Log($"Adding {obj}...");
        _inner.Add(obj);
        Console.Log($"{obj} addded.");
    }
}
// Done using the DI.
IRepositoty<User> repository = 
    // Add as many decorators as you want.
    new LoggingRepository<User>(
        new UserRepository(/* [...] */));

// And here is your add method wrapped with some logging :)
repository.Add(new User());
公共抽象类存储库
{
公共接口IRepositoryDependencies
{
IServiceA{get;}
IServiceB{get;}
}
受保护的存储库(IRepositoryDependencies)
{
/* ... */
}
}
由库用户创建的具体存储库:

// Abstract type
public interface IRepository<T>
{
    Add(T obj);
}

// Concete type
public class UserRepository : IRepository<User>
{
    public UserRepository(/* Specific dependencies */) {}

    Add(User obj) { /* [...] */ }
}

// Decorator
public class LoggingRepository<T> : IRepository<T>
{
    private readonly IRepository<T> _inner;

    public LoggingRepository<T>(IRepository<T> inner) => _inner = inner;

    Add(T obj) 
    {
        Console.Log($"Adding {obj}...");
        _inner.Add(obj);
        Console.Log($"{obj} addded.");
    }
}
// Done using the DI.
IRepositoty<User> repository = 
    // Add as many decorators as you want.
    new LoggingRepository<User>(
        new UserRepository(/* [...] */));

// And here is your add method wrapped with some logging :)
repository.Add(new User());
公共类FooRepository:存储库
{
受保护的存储库(IRepositoryDependencies):
基础(依赖项)
{
/* ... */
}
}
专业人士

  • 如果将依赖项添加到基类,则派生类不会中断
缺点

  • 如果添加依赖项,则必须修改
    IRepositoryDependencies
    接口的实现
  • 没有解释如何使用Castle DynamicProxy 2(对我来说这是一种未知的技术)动态生成服务聚合器
2.建造者模式 也许可以删除基本存储库构造函数并引入构建器模板来创建存储库,但要使此解决方案起作用,构建器必须是可继承的,以允许用户输入其存储库自己的依赖项

专业人士

  • 如果将依赖项添加到基类,则派生类不会中断
  • 存储库构造由另一个类管理
缺点

  • 用户必须为要创建的每个存储库创建一个生成器
  • 使用命名约定通过DI注册每个存储库变得越来越困难
3.属性注入 也许可以选择删除基本存储库构造函数并配置DI以使用属性注入

专业人士

  • 如果将依赖项添加到基类,则派生类不会中断
缺点

  • 我认为财产设定者必须公开
结论 在一个坚实的世界里,是否有任何上述解决方案是可以接受的?如果不是的话,你们有什么解决办法吗?非常感谢你的帮助

结论“我只限于永远不更改基类构造函数”纯粹是证明IoC容器“模式”有多重是有毒的

假设您有一个asp应用程序,并且希望能够以每次his会话转到新文件时的方式为特定用户启用日志记录。使用IoC容器/服务定位器/ASP控制器构造函数是不可能实现的。您可以做什么:在每次会话开始时,您应该创建这样的记录器,并将其准确地传递给所有构造函数(服务实现等)。没有其他办法。IoC容器中没有“每会话”生命周期这样的东西,但这只是实例自然应该存在于ASP中的一种方式(意味着多用户/多任务应用程序)

如果您没有通过构造函数使用DI,那么您肯定是做错了什么(对于ASP.CORE和EF.CORE来说,这是正确的-不可能看到他们如何用抽象泄漏折磨每个人和他们自己:您能想象添加自定义记录器会破坏DbContext,这是正常的吗


仅从DI配置或动态插件获取(但如果您没有动态插件,请不要考虑任何依赖关系,“因为它可能是动态插件”)然后通过构造函数执行所有DI标准经典方法。

正如您所要求的,这里是一个通过组合而不是继承来解决此问题的非常基本和粗糙的示例

public class RepositoryService : IRepositoryService
{

    public RepositoryService (IServiceA serviceA, IServiceB serviceB) 
    {
        /* ... */
    }

    public void SomeMethod()
    {
    }     
}

public abstract class Repository
{
    protected IRepositoryService repositoryService;

    public (IRepositoryService repositoryService)   
    {
      this.repositoryService= repositoryService;
    }

    public virtual void SomeMethod()
    {
          this.repositoryService.SomeMethod()

          .
          .
    }
}

public class ChildRepository1 : Repository
{

    public (IRepositoryService repositoryService)  : base (repositoryService)
    {
    }

    public override void SomeMethod()
    {
          .
          .
    }
}

public class ChildRepository2 : Repository
{

    public (IRepositoryService repositoryService, ISomeOtherService someotherService)   : base (repositoryService)
    {
          .
          .
    }

    public override void SomeMethod()
    {
          .
          .
    }
}
现在,这里的抽象基类和每个子存储库类将只依赖于
IRepositoryService