How to return multiple types of data in C#


How to return multiple types of data in C#



I do return different instances of service depending on a enum in my application:


public (????) CurrentService
{
get
{
switch (CurrentServiceEnum)
{
case ServiceType.ServiceA:
return IoC.ServiceA;
case ServiceType.ServiceB:
return IoC.ServiceB;
case ServiceType.ServiceC:
return IoC.ServiceC;
}
}
}



Each of that service has it's own implementation of RemoveAccount method, taking different type argument.


RemoveAccount


internal class ServiceA_AccountDataModel { [..] }
internal class ServiceB_AccountDataModel { [..] }
internal class ServiceC_AccountDataModel { [..] }

public class ServiceA {
public void RemoveAccount(ServiceA_AccountDataModel model) { [...] }
}
public class ServiceB {
public void RemoveAccount(ServiceB_AccountDataModel model) { [...] }
}
public class ServiceC {
public void RemoveAccount(ServiceC_AccountDataModel model) { [...] }
}



What I want to achieve here, is to be able to call a RemoveAccount method apart of the current service returned so that while passing the account of ServiceC_AccountDataModel is should automatically resolve to IoC.ServiceC.


RemoveAccount


account


ServiceC_AccountDataModel


IoC.ServiceC


// account is an instance of ServiceC_AccountDataModel so it should assume that CurrentService is the instance of ServiceC
CurrentService.RemoveAccount(account);



Is there a way to achieve something like that in C#?





Polymorphism C# Programming Guide and Interfaces C# Programming Guide
– TheGeneral
Jun 29 at 10:46






If you know that account is of type ServiceC_AccountDataModel why don't you just call IoC.ServiceC.RemoveAccount(account); ???
– Spotted
Jun 29 at 11:05


account


ServiceC_AccountDataModel


IoC.ServiceC.RemoveAccount(account);




1 Answer
1



One way to achieve this is for all the services to implement a common interface:


public interface IAccountRemovalService<T>
{
void RemoveAccount<T>(T model);
}

public class ServiceA : IAccountRemovalService<ServiceA_AccountDataModel>
{
public void RemoveAccount<ServiceA_AccountDataModel>(ServiceA_AccountDataModel model)
{
}
}

public class ServiceB : IAccountRemovalService<ServiceB_AccountDataModel>
{
public void RemoveAccount<ServiceB_AccountDataModel>(ServiceA_AccountDataModel model)
{
}
}



In order for this to work, you do need there to be something in common between each of your model types, such as a base class like AccountModelDataBase:


AccountModelDataBase


public class ServiceA_AccountDataModel : AccountDataModelBase {}

public class AccountDataModelBase {}



Once you've got that, it becomes possible to re-write your CurrentService property along these lines:


CurrentService


public IAccountRemovalService<AccountDataModelBase> CurrentService
{
get
{
IAccountRemovalService<AccountDataModelBase> returnedValue = null;
switch (CurrentServiceEnum)
{
case ServiceType.ServiceA:
returnedValue = IoC.ServiceA as IAccountRemovalService<AccountDataModelBase>;
break;
case ServiceType.ServiceB:
returnedValue = IoC.ServiceB as IAccountRemovalService<AccountDataModelBase>;
break;
case ServiceType.ServiceC:
returnedValue = IoC.ServiceC as IAccountRemovalService<AccountDataModelBase>;
break;
}
return returnedValue;
}
}



This does involve quite a few changes to your code, adding the interface and the base class, but it does give you a bit of an advantage as now you can ensure (by virtue of adding new members to IAccountRemovalService) that all your implementations of a service that have the RemoveAccount method remain in lock-step with regards to methods that they implement.


RemoveAccount



One small side note, having the property that you're switching on called CurrentServiceEnum doesn't quite sit right because of the Enum suffix on it, that'd probably be something to consider removing - but that's just my opnion! =)


CurrentServiceEnum


Enum





And how would you get the CurrentService property to work with this?
– DavidG
Jun 29 at 10:49


CurrentService





The cast in the last block of code will return null now.
– DavidG
Jun 29 at 11:02





You also have a redundant generic type specified in the method inside IAccountRemovalService that hides the outer type.
– DavidG
Jun 29 at 11:03


IAccountRemovalService





Thank you for your reply. One thing I'm confused about is this line: taking generic type: public class ServiceA : IAccountRemovalService<ServiceA_AccountDataModel>. In fact, it can take whatever type and still be working fine: pastebin.com/raw/6jmSZRza Why is that?
– Rusco
Jun 29 at 11:30



public class ServiceA : IAccountRemovalService<ServiceA_AccountDataModel>





@Rusco Because there is no constraint on the generic type, you can use anything. You could change it to public interface IAccountRemovalService<T> where T : AccountDataModelBase to restrict it. However, the code in this answer doesn't work because it relies on the IAccountRemovalService interface being covariant which it isn't.
– DavidG
Jun 29 at 12:10


public interface IAccountRemovalService<T> where T : AccountDataModelBase


IAccountRemovalService






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Comments

Popular posts from this blog

paramiko-expect timeout is happening after executing the command

how to run turtle graphics in Colaboratory

Export result set on Dbeaver to CSV