Tomimotmot
Tomimotmot

Reputation: 49

Interface with 3 different return values

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

Upvotes: 0

Views: 75

Answers (2)

Joelius
Joelius

Reputation: 4339

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.

Upvotes: 1

juharr
juharr

Reputation: 32296

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(){...}    
}

Upvotes: 1

Related Questions