1

I have a list of class that implement an interface, like this:

pulic interface ISample 
{
 public int Id { get; set; }
}
pulic class SampleA : ISample {}
pulic class SampleB : ISample {}
pulic class SampleC : ISample {}

Life time of these classs are Transient. I create a wrapper for created instances, like this:

public class Wrapper
{
   private IEnumerable<ISample> _Samples;
   public Wrapper(IEnumerable<ISample> Samples)
   {
      _Samples = Samples;
   }

   public void InstanceGenerator(int Id)
   {
     ISample MySample = _Samples.FirstOrDefault(s => s.Id == Id);
     //do somethings...
   }
}

Life time of Wrapper class is singleton. I would like that every time that I call "InstanceGenerator", it creates a new instance but it only creates one instance and every time returns that.

Aage
  • 5,932
  • 2
  • 32
  • 57
Ali Jafari
  • 100
  • 8
  • You'll need to register a factory method (i.e. some kind of delegate that returns an `ISample` according to some conditions) and inject that instead. – ProgrammingLlama Mar 09 '22 at 06:00
  • Could you show an example of use? – tymtam Mar 09 '22 at 06:11
  • Why the `IEnumerable<>`? Surely `IReadOnlyList<>` would be better. Would hate to have multiple evaluations of `IEnumerable<>` due to an incorrectly-configured DI container. Pretty sure `_Samples.FirstOrDefault()` will result in multiple evaluations –  Mar 09 '22 at 06:11
  • Could you show how you wire up `IEnumerable Samples` in your dependency injection? – Aage Mar 09 '22 at 06:45
  • Which DI Container, if any, are you using? The answer highly depends on the used DI Container. – Steven Mar 09 '22 at 15:26
  • Related: https://stackoverflow.com/questions/57758285/conditional-dependency-resolver-on-run-time-net-core/57790127#57790127 – Steven Mar 09 '22 at 15:28

1 Answers1

1

Instead of registering the types directly, you'd need to create a factory that creates new instances in a method call.

The following sample is based on your code, but also shows some differences. In addition to the ISample implementations and the wrapper, a factory is registered in the DI container. It defines a GenerateSamples method that uses the service provider to create new instances when called:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddTransient<ISample, SampleA>();
builder.Services.AddTransient<ISample, SampleB>();
builder.Services.AddSingleton<Wrapper>();
builder.Services.AddSingleton<SampleFactory>();

var app = builder.Build();

var wrapper = app.Services.GetRequiredService<Wrapper>();
wrapper.InstanceGenerator();
wrapper.InstanceGenerator();

class Wrapper
{
    private readonly SampleFactory _factory;

    public Wrapper(SampleFactory factory)
    {
        _factory = factory;
    }

    public void InstanceGenerator()
    {
        var samples = _factory.GenerateSamples();
        foreach(var sample in samples)
            Console.WriteLine($"Type: {sample.GetType().Name}, Id: {sample.InstanceId}");
    }
}

class SampleFactory
{
    private readonly IServiceProvider _serviceProvider;

    public SampleFactory(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public IEnumerable<ISample> GenerateSamples()
    {
        return _serviceProvider.GetRequiredService<IEnumerable<ISample>>();
    }
}

interface ISample { public Guid InstanceId { get; }}

class SampleA : ISample { public Guid InstanceId { get; set; } = Guid.NewGuid(); }
class SampleB : ISample { public Guid InstanceId { get; set; } = Guid.NewGuid(); }

If you run the sample, you can check the InstanceId to verify that a new instance is used in the InstanceGenerator method every time.

Markus
  • 20,838
  • 4
  • 31
  • 55
  • Thank you, but I dont want every time call "GenerateSamples()". Is there any way? – Ali Jafari Mar 09 '22 at 08:20
  • Can you change the lifetime of the wrapper to Transient or alternatively Scoped? This way, a new instance of Wrapper would be created for each request with new instances of the samples also. – Markus Mar 09 '22 at 08:35
  • If the Wrapper is a Singleton, it is (of course) created only once, so that DI will only once create the samples for the Wrapper class (and new ones if you inject the samples in some other class). The factory method changes this and creates the instances on the fly. – Markus Mar 09 '22 at 08:37