IIndex<K,V> 何时实例化其已解析的组件?

When does IIndex<K,V> instanciates its resolved components?

我搜索了与此问题相关的主题,但没有找到我想要的答案。 如果已经说过,请提前道歉。

让我们提出我的问题: 我有一个具体的 class,我们称它为 BLLClass,我通过构造函数在其上注入了 IRepository 的两个实现。 这些实现中的每一个都有自己的 DbContext 类型。 我想随时访问这两个 IRepository,以便能够随时对任何数据库执行操作,并在我完成后处理它们。 最初,我选择了类似的东西:

public BLLClass : IDisposable
{
    private Dictionary<eBaseSQL,IRepository<SomeObjectType>> Repositories;

    public BLLClass(IIndex<eBaseSql, IRepository<SomeObjectType> repositories)
    {
        Repositories = new Dictionary<eBaseSQL, IRepository<SomeObjectType>>();
        Repositories.Add(eBaseSQL.DatabaseOne, repositories[eBaseSQL.DatabaseOne]);
        Repositories.Add(eBaseSQL.DatabaseTwo, repositories[eBaseSQL.DatabaseTwo]);
    }

    public void Dispose()
    {
        foreach(IRepository<SomeObjectType> Repository in Repositories.Values)
        {
            Repository.Dispose();
        }   
    }
}

这工作正常,完全符合我的要求。 但是,我发现将我的实现添加到字典中有点难看,而 Autofac 提供了 IIndex,它不是字典,但看起来像一个字典。

所以这是我的问题: 我可以像使用 Dictionary 一样使用 IIndex 吗? 我的 IRepository 的具体实现何时被实例化? 每次我这样做都会创建一个新对象

// Let's say that "repositories" is a IIndex<K,V>
IRepository<SomeObjectType> someRepository = repositories[someEnum.SomeValue];

或者它总是给出相同的对象? 这真的让我很担心,因为如果 IIndex 在我每次使用时都实例化一个新的存储库,我将无法在之后处理它们。

感谢您的宝贵时间,很抱歉我的英语很明显,不是最好的。

如您所说,注入的 IIndex 确实像工厂一样运作。有

// Let's say that "repositories" is a IIndex<K,V>
IRepository<SomeObjectType> someRepository = repositories[someEnum.SomeValue];

这将 return 一个新的或现有的对象,具体取决于所有内容的注册方式。默认情况下,每次调用 repositories[someEnum.SomeValue] 时都会得到一个新对象。

关于处置,我认为你可以利用几个内置的 Autofac 选项之一来获得你想要的行为,如果你将你的 Repositories 字段切换到这个:

public BLLClass : IDisposable
{
    private IIndex<eBaseSQL,IRepository<SomeObjectType>> Repositories;

第一个问题:对于 BLLClass 在其生命周期内执行的所有操作,每种类型的回购是否重要?每次使用它们时创建对象(例如您的存储库)的开销通常很小,并且使用较短寿命的对象有助于使事情变得简单和干净。在这种情况下,如果您的回购注册是 InstancePerDependency(这也是默认设置),在您的 BLLClass 中,操作将如下所示:

public void DoStuff()
{
    using (var repo = Repositories[eBaseSql.SomeKey])
    {
    }
}

因此每次您请求时都会重新创建存储库,您可以使用 using 安全地自行处理每个实例。这仍然可以多次解决 repos,例如:

public void DoStuff()
{
    using (var repo = Repositories[eBaseSql.SomeKey]) { }
    using (var sameRepoAgainButNew = Repositories[eBaseSql.SomeKey]) { }
}

另一种方法,如果在单个 BLLClass 的生命周期内确实需要每个存储库的单个实例用于任何调用,您可以使用 Autofac 的 [=27] 注册您的 IRepository 实现=]:

builder.RegisterType<Repository<SomeObjectType>>()
    .Keyed<IRepository<SomeObjectType>>(eBaseSql.SomeKey)
    .InstancePerLifetimeScope();

那么如果在 BLLClass 你有:

public void DoStuff()
{
    var repo = Repositories[eBaseSql.SomeKey];
}

该回购实例应在 BLLClass 生命周期结束时处置。假设 BLLClass 本身是从一个以某种方式处理的范围创建的,一个非常简单的例子是:

using (var scope = container.BeginLifetimeScope())
{
    var bll = scope.Resolve<BLLClass>();
    bll.DoStuff();
}

注入到 BLLClass 中的 IIndex<> 的实现存储了对组件上下文的引用,该组件上下文在释放外部作用域时被释放,这反过来将释放任何子对象实施 IDisposable(参见 https://autofaccn.readthedocs.io/en/latest/lifetime/disposal.html#automatic-disposal)。在这种情况下,这是我们生成的存储库。例如:

using (var scope = container.BeginLifetimeScope())
{
    var bll = scope.Resolve<BLLClass>();
    bll.DoStuff();      // do something using our first repo implementation
    bll.DoMoreStuff();  // do something else using the same type of repo
}                       // here the scope is disposed, taking any generated repos with it

public void DoStuff()
{
    var repo = _repositories[eBaseSql.SomeKey];
    // some actions here
}

public void DoMoreStuff()
{
    var repo = _repositories[eBaseSql.SomeKey];    // the same repo as used in DoStuff will be returned here because of the .InstancePerLifetimeScope registration
}

使用 Autofac 的内置工厂通过其中一种方法动态创建对象也意味着您不会创建任何最终未使用的存储库,这在您的初始实现中看起来是可能的。