Ever run into a sit­u­a­tion where your appli­ca­tion needs to use a type for its inter­nal work­ing but occa­sion­ally need to con­vert that type into another just so it can be passed to another appli­ca­tion which doesn’t under­stand some of the base types we have in the .Net space?

Con­sider the exam­ple below, where the Player is a type in my prob­lem domain, but I need to com­mu­ni­cate infor­ma­tion about the player with a non-.Net client which doesn’t have the Guid type, so I need to have a Play­erDTO type used exclu­sively for mes­sage 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 prob­lem here is that there is no easy way to con­vert the Player type to Play­erDTO and every time I want to cre­ate a new Play­erDTO object I need to man­u­ally copy the val­ues from Player into PlayerDTO’s con­struc­tor, and my appli­ca­tion needs to know that it needs to con­vert Player.PlayerID into a string.

A cleaner solu­tion here is to over­load either the implicit or explicit con­verter so you can sim­ply cast a Player object into a Play­erDTO 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());
}

Fur­ther more, this allows you to eas­ily con­vert an array of Player objects into an array of Play­erDTO objects:

// use Array.ConvertAll
PlayerDTO[] playerDTOs = Array.ConvertAll(players, p => (PlayerDTO) p);
// use Linq
playerDTOs = players.Select(p => (PlayerDTO) p).ToArray();

No Inter­face types allowed

One thing to bear in mind when using the implicit/explicit oper­a­tors is that you won’t be able to use inter­face types, and the rea­son is spec­i­fied in Sec­tion 10.9.3 of the C# spec.

In short, defin­ing an implicit or explicit con­ver­sion between ref­er­ence types gives the user the expec­ta­tion that there will be a change in ref­er­ence; after all, the same ref­er­ence can­not be both types. On the other hand, the user does not have the same expec­ta­tion for con­ver­sions between ref­er­ence types and inter­face types.

In these cases, you still have other ways to make type con­ver­sion cleaner and cen­tralised, for example:

Cre­ate a FromI­Player method


playerDTOs = iPlayers.Select(p => PlayerDTO.FromPlayer(p)).ToArray();

Put all con­ver­sions in a Play­er­Con­vert sta­tic object

If you have lots of types which can be con­verted to many types then it might be a cleaner solu­tion to just put all the con­ver­sions into one sta­tic object, like the System.Convert class. You then use it like this:


playerDTOs = iPlayers.Select(p => PlayerConvert.ToPlayerDTO(p)).ToArray();

Ref­er­ences:

StackOverflow question on why you can't use interface types with implicit/explicit operator
Share

2 Responses to “Controlling Type conversion in C#”

  1. […] Imag­ine if you have another class which does not inherit from MyClass but defines an explicit oper­a­tor which allows you to cast an instance of […]

  2. […] that there exists an explicit cast oper­a­tor that lets you con­vert a value of type T to type […]

Leave a Reply