Home > Net >  DI dotnet/C#: Resolve objects with (different) strings in constructor
DI dotnet/C#: Resolve objects with (different) strings in constructor

Time:12-03

I have a .Net Console Application using Configuration, DependencyInjection and Hosting, where I need to create several Objects, where each object is different depending on a passed string.

class Program
{
    static void Main(string[] args)
    {
        var configuration = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json", false)
            .Build();

        serviceCollection.AddSingleton<IMyService, MyService>();
        serviceCollection.AddSingleton<IOtherService, OtherService>();
        serviceCollection.AddTransient<IMyObject, MyObject>();
        ...


public class MyObject : IMyObject
{
    public string _aString {get; set;}

    public MyObject(string aString)
    {
        _aString = aString;
    }
}


public class MyService : IMyService
{
    private IMyObject _objectA;
    private IMyObject _objectB;
    private readonly IOtherService _otherService;
    private readonly IOptions<FilePaths> _filePaths;

    public MyService(IOtherService otherService, IOptions<FilePaths> filePaths)
    {
        _otherService = otherService;
        // file path options contains 2 different file path strings
        _filePaths = filePaths;
    }

    public void WorkWithObjects()
    {
        // Instantiate Objects depending on File Path Strings
        // Do some work with my objects here
    }
}

Each string is a file path which defines the object, but I abstracted the behaviour in above example.

What is the best way to go about this? Is my design correct?
I did some research and tried to:

  • Instantiate Objects in MyService directly (this is bad, because it violates DI)
  • Create a MyObjectFactory as Service and directly instantiate Objects there (but now I need to change the Factory implementation if I was to change the MyObject implementation, so this also violates DI ?)
  • Work with ActivatorUtilities.CreateInstance() but I could not find a way to pass a string parameter
  • take out the string parameter from the object constructor and put it into a method, which I call upon instantiating the object (but this seems like it would not be very clean)

CodePudding user response:

First of all, there is no need to register MyObject in DI container: serviceCollection.AddTransient<IMyObject, MyObject>(); as you are planning to have multiple 'MyObject' instances based on configuration. I assume that you can have multiple file paths in the configuration.

Introducing separate IMyObjectsFactory interface is perfectly fine and doesn't violate any rule. The only responsibility of the Factory will be to create instances of IMyObject. Changing factory implementation when IMyObject implementation is changed is perfectly fine. You abstract creation of MyObject to factory.

public interface IMyObjectsFactory
{
    IEnumerable<IMyObject> Create();
}

public class MyObjectFactory : IMyObjectsFactory
{
    private readonly IOptions<FilePaths> _filePaths;

    public MyObjectFactory(IOptions<FilePaths> filePaths)
    {
         _filePaths = filePaths;
    }

    public IEnumerable<IMyObject> Create()
    {
        foreach(var path in _filePaths.Value.Paths)
        {
            yield return new MyObject(path)
        }
    }
}
  • Related