0

I have a customerservice for 6 different shops with 3 different shopystem apis, so I have 3 libs in my Project

Like

Shopsytem 1 -> (Lib1)
Shop A
Shop B
Shop C

Shopsystem 2 -> (Lib2)
Shop D
Shop E

Shosystem 3 -> (Lib3)
Shop F

I have a "Contactcontroller" in Lib1, Lib2/Lib3 inherited from Lib1

Now I need to call a function like

contractService.getContracts();

With my Interface

public interface IContractService
{
    List<ContractData> GetContracts()
}

In each Lib I have a class like

public Shopsystem1ContractService : IContractService {   
    List<ContractData> GetContracts(){...}
}

public Shopsystem2Contractservice : IContractService {
    List<ContractData> GetContracts(){...}    
}

public Shopsystem3ContractService : IContractService {
    List<ContractData> GetContracts(){...}    
}

But Now I need something like this:

public Shopsystem1ContractService : IContractService {   
    List<Shopsystem1ContractData> GetContracts(){...}
}

public Shopsystem2ContractService : IContractService {
    List<Shopsystem2ContractData> GetContracts(){...}    
}

public Shopsystem3contractservice : IContractservice {
    List<Shopsystem3ContractData> GetContracts(){...}    
}

Update:

Now I use a generic interface according to juharr and Julius:

    interface IContractService<TContract> where TContract : ContractData
{
     List<TContract> GetContracts();
}

public Shopsystem1ContractService : IContractService<Shopsystem1ContractData>
{   
    List<Shopsystem1ContractData> GetContracts(){...}
}

public Shopsystem2ContractService : IContractService<Shopsystem2ContractData>
{
    List<Shopsystem2ContractData> GetContracts(){...}    
}

public Shopsystem3contractservice : IContractservice<Shopsystem3ContractData>
{
    List<Shopsystem3ContractData> GetContracts(){...}    
}

IoCModule:

    ioc.Register<IContractService<Shopsystem1ContractData>, Shopsystem1contractservice>();
    ioc.Register<IContractService<Shopsystem2ContractData>, Shopsystem2contractservice>();
    ioc.Register<IContractServic<Shopsystem3ContractData>, Shopsystem2contractservice>(); 

But how can I implement this in my ContractController?

private readonly IContractService<ContractData> contract;


        public KontaktController(
            IContractService<ContractData> contract,
        {
            this.contract = contract;
        }

IContractService needs a type, how does it know Shopsystem{1-3}ContractData?

The easy way would be to create a Contractcontroller in Lib2 and Lib3, but I would be great if I could do that in my globallib (lib1). I have controllers in Lib 2 and Lib3, but only for explicit endpoints

1
  • I added a possible solution to my answer to try and answer your edit. Commented Jun 21, 2019 at 10:25

2 Answers 2

1

You can make the interface generic so you can specify the desired type in the implementations like this.

public interface IContractService<TData> where TData : ContractData
{
    List<TData> GetContracts();
}

public Shopsystem1ContractService : IContractService<Shopsystem1ContractData>
{   
    List<Shopsystem1ContractData> GetContracts(){...}
}

public Shopsystem2ContractService : IContractService<Shopsystem2ContractData>
{
    List<Shopsystem2ContractData> GetContracts(){...}    
}

public Shopsystem3contractservice : IContractservice<Shopsystem3ContractData>
{
    List<Shopsystem3ContractData> GetContracts(){...}    
}
Sign up to request clarification or add additional context in comments.

2 Comments

You might want to explain the where keyword as it is fairly crucial in this example.
private readonly IContract<ContractData> contract; public KontaktController( IContract<ContractData> contract, { this.contract = contract; } How does my controller know which Contract Data to call, Controller will call each time Contract Data ?
1

This looks like a case for generics.
You should make the IContractservice generic. Like this:

interface IContractservice<TContract> where TContract : ContractData
{
     List<TContract> GetContracts();
}

The where makes it so the generic type you pass in has to be derived from ContractData.

You would then implement it like this:

class Shopsystem1contractservice : IContractservice<Shopsystem1contractData>
{
     public List<Shopsystem1contractData> GetContracts()
     {

     }
}

Let's talk about your edit:

In the current situation, I'd say you can't do that. You are correct that there is no way of knowing which of the three should be injected. That's why you should do one of the following things:

  1. Put a more explicit type to inject so for example use IContractservice<Shopsystem1contractData> inside your controller.
  2. Register a certain type for IContract<ContractData> instead of a more explicit one.

Both of these probably break your system so why are you doing it like this? You will always need a way of choosing one of the three and you could (as mentioned in point 2) register the one to use if asked for the general one.

I think like this would make the most sense:

ioc.Register<IContract<ContractData>, Shopsystem2contractservice>(); 

The other three things you registered are redundant since you currently only seem to have one implementation of IContract<Shopsystem1ContractData>, etc. You do however have multiple implementations of IContract<ContractData> so that's what you should register.

You should also be able to register ContractData so everytime you ask for ContractData it'll take the one you defined (eg. Shopsystem1contractData).

There is a flaw in your design so it's very hard to determine which would be the correct solution for your case.

2 Comments

private readonly IContract<ContractData> contract; public KontaktController( IContract<ContractData> contract, { this.contract = contract; } How does my controller know which Contract Data to call, Controller will call each time Contract Data ?
Please edit your question if you add additional code :) Also I'm sorry but I don't quite understand what you mean by this. Why does the controller need to know the exact type of the Contract data?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.