StructureMap Generic Ctor Named Instance

Update

I solved this problem with the following code, but this is not the solution I'm looking for. This is still open generosity for a more general solution. If we ever have a table that is not intor stringfor a key value, we will have to add to this manually for it to work.

c.For(typeof(ILogDifferencesCommand<,>)).Use(typeof(LogDifferencesCommand<,>))
                .Ctor<ILogDifferencesLogger<int>>()
                .Named(AppSettingsManager.Get("logDifferences:Target"))
                .Ctor<string>()
                .Named(AppSettingsManager.Get("logDifferences:Target"));

Original question

I have three types of registrars, and I defined them with instance names in my container:

c.For(typeof(ILogDifferencesLogger<>))
    .Use(typeof(LogDifferencesAllLogger<>))
    .Named("all");
c.For(typeof(ILogDifferencesLogger<>))
    .Use(typeof(LogDifferencesNLogLogger<>))
    .Named("nlog");
c.For(typeof(ILogDifferencesLogger<>))
    .Use(typeof(LogDifferencesDatabaseLogger<>))
    .Named("database");

LogDifferencesCommandaccepts ILogDifferencesLogger<>as a single argument:

public LogDifferencesCommand(ILogDifferencesLogger<TKey> logDifferencesLogger)
{
    this.logDifferencesLogger = logDifferencesLogger;
}

How to configure correctly ILogDifferencesCommand<>to capture the right named instance based on application configuration? Right now I have something like this:

c.For(typeof(ILogDifferencesCommand<,>))
    .Use(typeof(LogDifferencesCommand<,>));

, , , Ctor<>, , Named Ctor .

, - , :

c.For(typeof(ILogDifferencesCommand<,>)).Use(typeof(LogDifferencesCommand<,>))
    .Ctor<ILogDifferencesLogger<int>>()
    .Named(AppSettingsManager.Get("logDifferences:Target"));

, TKey, .

public class LogDifferencesCommand<TModel, TKey> : ILogDifferencesCommand<TModel, TKey>
    where TModel : class, IIdModel<TKey>
{
    public LogDifferencesCommand(ILogDifferencesLogger<TKey> logDifferencesLogger)
    {
        this.logDifferencesLogger = logDifferencesLogger;
    }
}

public interface ILogDifferencesCommand<TModel, TKey>
    where TModel : class, IIdModel<TKey>
{
    List<LogDifference> CalculateDifferences(TModel x, TModel y);

    void LogDifferences(TModel x, TModel y, string tableName, string keyField, string userId, int? clientId);

    void RegisterCustomDisplayNameObserver(WeakReference<ICustomDisplayNameObserver<TModel>> observer);

    void RegisterCustomChangeDateObserver(WeakReference<ICustomChangeDateObserver<TModel>> observer);
}

public interface ILogDifferencesLogger<TKey>
{
    void LogDifferences(string tableName, string keyField, string userId, TKey id, List<LogDifference> differences, int? clientId);
}

TKey - IIdModel.

+4
2

, :

var loggers = new Dictionary<string, ConfiguredInstance>();
loggers.Add("all", c.For(typeof(ILogDifferencesLogger<>))
    .Use(typeof(LogDifferencesAllLogger<>)));
loggers.Add("nlog", c.For(typeof(ILogDifferencesLogger<>))
    .Use(typeof(LogDifferencesNLogLogger<>)));
loggers.Add("database", c.For(typeof(ILogDifferencesLogger<>))
    .Use(typeof(LogDifferencesDatabaseLogger<>)));
foreach (var kv in loggers) {
    // if you still need them named
    // if you only used names for this concrete scenario - you probably don't
    // so can remove it
    kv.Value.Named(kv.Key);
}
c.For(typeof(LogDifferencesCommand<>))
    .Use(typeof(LogDifferencesCommand<>))
    // add explicit instance as dependency
    .Dependencies.Add(typeof(ILogDifferencesLogger<>), loggers[AppSettingsManager.Get("logDifferences:Target")]); 

Update. , , LogDifferencesCommand . - ( , ) - ILogDifferencesLogger<>, - LogDifferencesCommand. , github. :

public class GenericTypesWorkaroundInstance : Instance
{
    private readonly Instance _target;
    private readonly Func<Type[], Type[]> _chooseTypes;
    public GenericTypesWorkaroundInstance(Instance target, Func<Type[], Type[]> chooseTypes) {
        _target = target;
        _chooseTypes = chooseTypes;
        ReturnedType = _target.ReturnedType;
    }

    public override Instance CloseType(Type[] types) {
        // close type correctly by ignoring wrong type arguments
        return _target.CloseType(_chooseTypes(types));
    }

    public override IDependencySource ToDependencySource(Type pluginType) {
        throw new NotSupportedException();
    }

    public override string Description => "Correctly close types over open generic instance";    
    public override Type ReturnedType { get; }
}

commandReg.Dependencies.Add(
    commandReg.Constructor.GetParameters().First(
        p => p.ParameterType.IsGenericType && p.ParameterType.GetGenericTypeDefinition() == typeof(ILogDifferencesLogger<>)).Name, 
        new GenericTypesWorkaroundInstance(
            loggers[AppSettingsManager.Get("logDifferences:Target")],
            // specify which types are correct
            types => types.Skip(1).ToArray()));

, , .

+3

StructureMap () , , , .

+2
source

Source: https://habr.com/ru/post/1690243/


All Articles