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#?
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.
Polymorphism C# Programming Guide and Interfaces C# Programming Guide
– TheGeneral
Jun 29 at 10:46