继承-实例化基类构造函数所需的派生类

时间:2019-10-10 17:33:16

标签: c# .net oop asp.net-core

我对OOP的基本概念缺乏了解。这是一个示例:

说我有一个基本存储库,它由3个不同的类派生。基类需要在构造函数中通过依赖注入注入dbContext。因此,每次我实例化子类时,子类都必须传递dbContext。要求很简单:基类应为子类实例化Context。那可能吗?我不希望子类担心上下文。我只想让他们打电话。

这是我的基础课。

        public class CastingBaseRepository<TEntity> : ICastingBaseRepository<TEntity> where TEntity : class, IEntity
    { 
        private readonly CastingContext _context;
        public CastingBaseRepository(CastingContext context) => _context = context ?? throw new ArgumentNullException(nameof(context));

        // Context property
        public CastingContext Context => _context;
}

以下是子类的情况:

         public class CommercialJobsRepository : CastingBaseRepository<Audition>, ICommercialJobsRepository
            { 
    /* I do not want to use base(context) here. I need a way for this class to just call Context property from the derived class.. Possible? */

                private CastingContext _context;
                public CommercialJobsRepository(CastingContext context) : base(context)
                {
                    _context = context;
                }

                public async Task<IList<OpenJobs>> GetOpenJobs()
                {
// test code
                    var tt = await _context.Audition.Take(10).ToListAsync();
                    return new List<OpenJobs>();
                }
            }

这是我的上下文课程

    public partial class CastingContext : DbContext
{
     public virtual DbSet<Audition> Audition { get; set; }
    public CastingContext(DbContextOptions<CastingContext> options) : base(options)
    {
    }
}

这是startup.cs

  public class Startup
    {

        public void ConfigureServices(IServiceCollection services)
        {

            // DB Context

            services.AddDbContextPool<CastingContext>(options => { options.EnableSensitiveDataLogging(); options.UseSqlServer(Configuration.GetConnectionString("dbCast")); });
           }
}

我正在使用策略模式来确定在运行时将访问哪个子类。那也需要CastingContext注入丑陋的构造函数。关键是,应该只有一个类将上下文公开给所有派生类,或者通过静态方法公开。您能帮我了解如何做吗?

这是我的策略课程:

  public class JobsStrategyContext
{
    private readonly CastingContext _context;

    private readonly Dictionary<eBreakdownTypes, IJobsRepository> Strategies =
        new Dictionary<eBreakdownTypes, IJobsRepository>();

    public JobsStrategyContext(CastingContext context)
    {
        _context = context;

        Strategies.Add(eBreakdownTypes.Ftv, new FtvJobsRepository(_context));
        Strategies.Add(eBreakdownTypes.Commercial, new CommercialJobsRepository(_context));
        Strategies.Add(eBreakdownTypes.Theatre, new TheatreJobsRepository(_context));
    }


    public async Task<IList<OpenJobs>> GetOpenJobsBySubType(eBreakdownTypes breakdownType)
    {
        return await Strategies[breakdownType].GetOpenJobs();
    }
}

3 个答案:

答案 0 :(得分:2)

不,您不能同时使用依赖注入在基类中硬编码依赖的实例化。如果要从外部使用者注入依赖性,则它需要通过派生的构造函数传递。

充其量,您可以传递一个服务定位器,基础构造函数然后使用该服务定位器来获取dbcontext,但是您仍在处理派生类中的服务定位器。但是service locators are no longer considered good practice因为它们具有显着的缺点,例如降低了可读性/可用性,并且在足够大的代码库中变得难以处理。
尽管从技术上讲它可以实现您想要的目标,但是不要开始使用静态服务定位器。成本远大于收益。

但是,问题的开始对我而言并不合理。如果您使用的是依赖注入,那么我假设您正在使用某种自动注入,而不必手动实例化所有依赖。
是的,您仍然需要提及dbcontext作为(派生的和基本的)构造函数参数,但是派生类不需要处理它(除了将其传递给基本的构造函数。这样做的工作量很小,并且允许在依赖注入方面获得最大的自由度。

继承是设计使然的方式。

答案 1 :(得分:1)

这是C#语言的功能限制。您没有必须在子类中提供与基类相同的构造函数,但是您必须满足基类中的那些构造函数。例如:

public class BaseClass
{
    public BaseClass(Dependency dep) {}
}

public class ChildClass
{
    public ChildClass(Dependency dep) : base(dep) {}
}

或者:

public class ChildClass
{
    public ChildClass() : base(new Dependency()) {}
}

无论哪种情况,您都必须以某种方式向基类构造函数提供Dependency实例,但是您可能选择不实际构造具有该依赖关系的子类,而是在内部获取它。

但是,实际上,DbContext之类的东西依赖于要注入的依赖项,它将需要一直携带该依赖项:您的子类将需要一个构造函数,可以按顺序对其进行注入然后传递给基类构造函数。

答案 2 :(得分:1)

您必须通过子类提供依赖项,因为在创建子类的实例时,基类也将被构造,因此必须提供依赖项。

当然,为了简化编码和管理这些依赖关系,您可以使用使用 Unity 之类的IoC容器来处理自动依赖关系注入(支持构造函数,属性的Unity Application依赖关系注入容器,以及方法调用注入)