Search code examples
c#.netdependency-injectioncastle-windsor

Resolve/register generic object by string value in Windsor


I have an interface IImportCommand<T>

public interface IImportCommand<T> where T : ImportModelBase
{
    DateTime Date { get; set; }
    List<T> Items { get; set; }
}

implemented object ImportEntityCommand<T>

public class ImportEntityCommand<T> : ICommand, IImportCommand<T> where T : ImportModelBase
{
    public DateTime Date { get; set; }
    public List<T> Items { get; set; }
}

and some models from ImportModelBase

UserImportModel : ImportModelBase
PersonImportModel : ImportModelBase

and for ImportEntityCommand

ImportUserCommand : ImportEntityCommand<UserImportModel>
ImportPersonCommand: ImportEntityCommand<PersonImportModel>

etc

To build ImportEntityCommand I want to do something like this when string parameter is "user"

new ImportUserCommand()
{
    Date = body.Date.ToUniversalTime(),
    Items = body.Data.Select(d => d.ToObject<UserImportModel>()).ToList()
}

and when "person" then

new ImportPersonCommand()
{
    Date = body.Date.ToUniversalTime(),
    Items = body.Data.Select(d => d.ToObject<PersonImportModel>()).ToList()
}

body is json from request.

Is it possible to register my interface and entities based on input strings to create desired command object?


The simplest solution would be to do it with a switch statement, but I would like something more elegant.


Solution

  • The commands should not be registered with Dependency Injection, but you could register a Factory that creates the commands based on input strings.

    One way to do this without using switch statements would be to add the factory methods to an internal Dictionary where the key is the input string.

    Maybe something like this could get you started;

    Factory (registered with DI)

    public interface ICommandFactory
    {
        ICommand Create(string type, DateTime dateTime, string json);
    }
    
    public class CommandFactory : ICommandFactory
    {
        private readonly Dictionary<string, Func<DateTime, string, ICommand>> _dictionary = new ()
        {
            { "user", (dateTime, json) => new ImportUserCommand(dateTime, json) },
            { "person", (dateTime, json) => new ImportPersonCommand(dateTime, json) }
        };
    
        public ICommand Create(string type, DateTime dateTime, string json) => _dictionary[type](dateTime, json);
    }
    

    Commands and models (not registered)

    public interface ICommand
    {
        DateTime Date { get; set; }
    }
    
    public class Command<T> : ICommand
    {
        protected Command(DateTime dateTime, string json) { /* Set data from json */ }
    
        public DateTime Date { get; set; }
        public List<T> Items { get; set; }
    }
    
    public class ImportUserCommand : Command<UserImportModel>
    {
        public ImportUserCommand(DateTime dateTime, string json) : base(dateTime, json) { }
    }
    
    public class ImportPersonCommand : Command<PersonImportModel>
    {
        public ImportPersonCommand(DateTime dateTime, string json) : base(dateTime, json) { }
    }
    
    public class UserImportModel { }
    public class PersonImportModel { }