Controlling Type conversion in C#

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