C# 8 - membres Readonly sur Struct

Au moment de l'écriture de cet article C# 8 n'est pas encore sorti en finale mais est disponible en preview (preview-5 actuellement, vous avez le lien de téléchargement en bas de l'article). Cette version va amener beaucoup de nouveautés (commme d'habitude !!) et combiné avec la disponibilité prochaine de dotnet core 3 qui semble offrir un runtime encore plus performant, vous n'aurez plus d'excuse pour ne pas utiliser C# 8.

Dans ce second post sur les nouveautés de C# 8, nous allons nous intéresser à une petite évolution mais qui apporte plus de clarté à vos collègues et plus de sécurité à votre code en indiquant au compilateur votre intention lorsque vous definissez des membres sur une struct.

Précédemment nous pouvions utiliser le mot clé readonly dans les 3 cas suivants :

  • pour un champ, ce qui impliquait que l'on pouvait modifier ce champ uniquement dans le constructeur ou dans la déclaration du champ,
  • pour une struct complète, ce qui marquait la structure immutable,
  • pour un ref return on pouvait signaler que la valeur retournée par une méthode ne pouvait pas être modifiée.

C# 8 va nous permettre d'être plus fin dans le cas d'une struct en ne le précisant que sur certains de ses membres.

Nous allons prendre l'exemple suivant qui définit une struct Money

public enum Currency
{
	EUR,
	USD
}

public struct Money
{
  public double Montant { get; set; }
  public Currency Currency { get; set; }
  public override string ToString() => $"{Montant} {Currency}";
}

Si nous essayons d'executer notre code à l'aide du code suivant :

    class Program
    {
        static void Main(string[] args)
        {
			var m = new Money {Montant = 2.3, Currency = Currency.EUR};
            Console.WriteLine(m);
        }
    }

Nous obtenons la sortie suivante dans une application console :

2,3 EUR

Comme c'est souvent le cas la méthode ToString() ne modifie pas la valeur des champs. Nous pouvons à partir de C# 8 préciser que cette méthode est readonly.

	public readonly override string ToString() =>	$"{Montant} {Currency}";

L'exécution du nouveau code n'a aucune incidence mais véhicule l'information que cette méthode ne doit pas modifier ses membres. Mais cela va plus loin. Imaginons que nous ayons une méthode qui affiche cette information en USD.

	public float ToUSD() =>	Montant*1.15;
	public readonly override string ToUSDString() => $"{ToUSD()} USD";

Si nous tentons de compiler ce programme nous obtenons le warning suivant :

Program.cs(17,51): warning CS8656: Call to non-readonly member 'Money.ToUSD()' from a 'readonly' member results in an implicit copy of 'this'.

Oups! Warning, Implicit copy, cela n'a pas l'air bon. Le soucis est que nous appelons une méthode qui n'est pas readonly depuis une méthode readonly et le compilateur nous prévient. Ceci n'est qu'un warning mais j'aurais préféré que ce soit directement une erreur (nous pouvons toujours dans Visual Studio traiter les warning comme des erreurs dans les propriétes du projet). Pour corriger le problème il suffit d'ajouter le mot clé readonly à nouveau sur notre méthode ToUSD et tout est corrigé.

Voila pour ce court article, je veux ajouter que même si cela vous parait être une petite fonctionnalité, je veux vraiment insister sur le fait qu'elle vous aidera à avoir du code plus sûr et plus performant. Donc comme d'habitude n'attendez pas pour essayer et l'adopter.

Liens