1

Ok, the Title already sounds a bit silly, but I don't even know how to describe this better. So let's try to outline the problem.

What I've figured out so far is the following, which is working:

Given I have an interface like that

public interface ISomeService {}

then I can dynamically add the service with it's implementation like that

var vendorService = assembly?.GetType($"{vendor}.Services.{vendor}Service");

// null-check here

services.TryAddSingleton<ISomeService>(_ =>
   (ISomeService) Activator.CreateInstance(vendorService, _config)!);

(I need to do this, because at Compile-time I do not yet know which service will be finally loaded. This information is coming from a command-line-argument)

So far so good...

Now I have another Service that looks like this:

public interface IInformationService<T>
{
    public string? Serialize(T vendorInformation, bool isFile);

    public T Deserialize(string? filename = null);
}

In this case I don't know how to add the Service to a collection since...

var vendorInfoService = assembly?.GetType($"{vendor}.Services.InformationService<{vendor}>");

// null-check here

services.TryAddSingleton<IInformationService< [???] >>(_ =>
   (IInformationService< [???] >) Activator.CreateInstance(vendorInfoService, _config)!);

... I don't know how to pass T down, which is not known until it is clear what vendor is.

So given the vendor (which is not known at compile-time) is "Foo" then the actual Type of the above vendorService would be FooService, the Information-Service would be InformationService<FooModel>.

But I'm really not sure how to implement it.

Maybe you can help me out. Thanks in advance :)

bquarta
  • 559
  • 6
  • 19

1 Answers1

2

That should be possible like this:

builder.Services.AddSingleton(typeof(IGenericService<>),
    p => /* do something to get service */);

or, if you want to get rid of the Activator, just like this:

var type = assembly.GetType($"Generic{vendor}Service"); // or get the type somehow
builder.Services.AddSingleton(typeof(IGenericService<>), type);

The problem here is, that you don't get any information about the "T", so you somehow have to make sure that for every T you try to inject in one of your services, there is a binding that matches said T.

A better way would most likely be to reiterate over this and define a service interface without the generic and design an IVendorInformationModel instead, which is passed to Serialize or provided by Deserialize.

t.haeusler
  • 76
  • 5
  • Thanks a lot for your answer! I will try the way you suggested as soon as possible, and come back to you to let you know if it worked for me. I was thinking about your last approach already, but my main problem is, that the service addresses a legacy-structure of our software, with many different (in terms of it's structure) XML-Files, that do the same job but look totally different, and I'm aiming for a refactoring, that unifies this a bit more. The service is kind of an "adapter", and a non-generic implementation (IVendorInformationModel) can hardly be designed under the same contract. – bquarta Mar 07 '23 at 14:35