相同接口的 StructureMap 但具有不同构造函数参数的多个实例

StructureMap for same interface but with multiple instances for different constructor parameters

我正在为 StructureMap 苦苦挣扎。我需要确保每个 HttpContextLifecycle 获得一个实例,但每个构造函数参数获得一个实例。我们原来的工作代码是:

注册表:

For<IGenericFormInitialValueResolver<SalesforceEditContactBlock>>()
    .LifecycleIs<HttpContextLifecycle>()
    .Use<SalesforceEditFormInitialValueResolver>();

In FormInitialValueResolverFactory(actualType 是 IGenericFormInitialValueResolver 通用类型):

if (_iocContainer.TryGetInstance(actualType) is IGenericFormInitialValueResolver returnValue)
{
    if (returnValue is ISalesforceInstanceFormInitialValueResolver salesforceInstanceFormInitialValueResolver &&
        salesforceInstanceName.HasValue)
    {
        salesforceInstanceFormInitialValueResolver.SalesforceInstanceName = salesforceInstanceName.Value;
    }
    return returnValue;
}

现在我需要更改它,以便在构造函数中给出 SalesforceInstanceName。但我仍然希望为每个 SalesforceInstanceName(它是一个具有 2 个值的枚举)实例缓存 HttpContextLifecycle。所以我通过 TryGetInstance 重载传递了参数:

ExplicitArguments args = new ExplicitArguments();
args.Set(salesforceInstanceName ?? SalesforceInstanceName.Undefined);
if (_iocContainer.TryGetInstance(actualType, args) is IGenericFormInitialValueResolver returnValue)
{
    return returnValue;
}

它的工作方式是我得到了实例,但总是一个新实例,所以它不会在每个 http 生命周期中缓存。

所以我尝试更改注册表:

foreach (SalesforceInstanceName salesforceInstanceName in (SalesforceInstanceName[])Enum.GetValues(typeof(SalesforceInstanceName)))
{
    For<IGenericFormInitialValueResolver<SalesforceEditContactBlock>>()
        .Add<SalesforceEditFormInitialValueResolver>().Ctor<SalesforceInstanceName>()
        .Is(salesforceInstanceName)
        .LifecycleIs<HttpContextLifecycle>();
}

但是现在TryGetInstance总是returnsnull.

如果您通过 ExplicitArguments 传递自定义构造函数参数,StructureMap 将始终构建一个新实例。您可能想像这样使用命名实例:

foreach (SalesforceInstanceName salesforceInstanceName in (SalesforceInstanceName[])Enum.GetValues(typeof(SalesforceInstanceName)))
{
    For<IGenericFormInitialValueResolver<SalesforceEditContactBlock>>()
        .Use<SalesforceEditFormInitialValueResolver>()
        .Ctor<SalesforceInstanceName>()
        .Is(salesforceInstanceName)
        .Named(salesforceInstanceName.ToString())
        .LifecycleIs<HttpContextLifecycle>();
}

你基本上是说,对于 SalesforceInstanceName 枚举的每个值,你都注册了 SalesforceEditFormInitialValueResolver 的单独命名实例(具有所述枚举值的名称),并将该枚举值作为构造函数参数。

然后解析,而不是使用ExplicitArguments,使用名称:

container.TryGetInstance(actualType, salesforceInstanceName.ToString());

在看到 (我现在将检查)之前,我已经有了一个可行的解决方案:

IGenericFormInitialValueResolver genericFormResolver = _iocContainer.GetAllInstances(actualType)
    .OfType<IGenericFormInitialValueResolver>()
    .FirstOrDefault(resolver => resolver is ISalesforceInstanceFormInitialValueResolver sr && sr.SalesforceInstanceName == salesforceInstanceName);
if (genericFormResolver != null)
{
    return genericFormResolver;
}

所以我正在使用 iocContainer.GetAllInstances 获取所有 (3) 个实例,然后过滤我需要的那个。我想 Evk 的方法更简洁,我可能更有效率。

更新:我测试了 Evk 的方法,它运行良好。我总是为每个 SalesforceInstanceName 得到一个缓存实例,它比我的更好的是:只构建所需的实例而不是全部。我保留这个答案以防有人需要替代方案。