Yan Cui
I help clients go faster for less using serverless technologies.
Ever run into a situation where your application needs to use a type for its internal working but occasionally need to convert that type into another just so it can be passed to another application which doesn’t understand some of the base types we have in the .Net space?
Consider the example below, where the Player is a type in my problem domain, but I need to communicate information about the player with a non-.Net client which doesn’t have the Guid type, so I need to have a PlayerDTO type used exclusively for message passing:
public sealed class Player { public Player(string name, long score) { Name = name; Score = score; ID = Guid.NewGuid(); } public string Name { get; private set; } public Guid ID { get; private set; } public long Score { get; private set; } } public sealed class PlayerDTO { public PlayerDTO(string name, long score, string id) { Name = name; Score = score; ID = id; } public string Name { get; private set; } public string ID { get; private set; } // client is not .Net based so no Guid there public long Score { get; private set; } }
The problem here is that there is no easy way to convert the Player type to PlayerDTO and every time I want to create a new PlayerDTO object I need to manually copy the values from Player into PlayerDTO’s constructor, and my application needs to know that it needs to convert Player.PlayerID into a string.
A cleaner solution here is to overload either the implicit or explicit converter so you can simply cast a Player object into a PlayerDTO object:
// Overload explicit cast converter to allow easy conversion from a Winner to WinnerAmfvo object public static explicit operator PlayerDTO(Player player) { return new PlayerDTO(player.Name, player.Score, player.PlayerID.ToString()); }
Further more, this allows you to easily convert an array of Player objects into an array of PlayerDTO objects:
// use Array.ConvertAll PlayerDTO[] playerDTOs = Array.ConvertAll(players, p => (PlayerDTO) p); // use Linq playerDTOs = players.Select(p => (PlayerDTO) p).ToArray();
No Interface types allowed
One thing to bear in mind when using the implicit/explicit operators is that you won’t be able to use interface types, and the reason is specified in Section 10.9.3 of the C# spec.
In short, defining an implicit or explicit conversion between reference types gives the user the expectation that there will be a change in reference; after all, the same reference cannot be both types. On the other hand, the user does not have the same expectation for conversions between reference types and interface types.
In these cases, you still have other ways to make type conversion cleaner and centralised, for example:
Create a FromIPlayer method
playerDTOs = iPlayers.Select(p => PlayerDTO.FromPlayer(p)).ToArray();
Put all conversions in a PlayerConvert static object
If you have lots of types which can be converted to many types then it might be a cleaner solution to just put all the conversions into one static object, like the System.Convert class. You then use it like this:
playerDTOs = iPlayers.Select(p => PlayerConvert.ToPlayerDTO(p)).ToArray();
References:
StackOverflow question on why you can't use interface types with implicit/explicit operator
Whenever you’re ready, here are 3 ways I can help you:
- Production-Ready Serverless: Join 20+ AWS Heroes & Community Builders and 1000+ other students in levelling up your serverless game. This is your one-stop shop for quickly levelling up your serverless skills.
- I help clients launch product ideas, improve their development processes and upskill their teams. If you’d like to work together, then let’s get in touch.
- Join my community on Discord, ask questions, and join the discussion on all things AWS and Serverless.
Pingback: Converting List<T> using covariance | theburningmonk.com
Pingback: What does this F# code look like in Erlang – Part 2 of N | theburningmonk.com