Ecrire du beau code en C# 6 avec .Net 4.6 sur Unity

Depuis la version 2017.1 il est désormais possible d’activer .Net 4.6 et d’utiliser toutes les nouveautés du langage C# jusqu’à sa version 6. Avant cette mise à jour, tous les développeurs Unity étaient limités à .Net 2.0 sortie en 2006 ! Je vous laisse imaginer ce que presque 10 ans d’évolutions vont apporter à votre productivité 🙂 Par exemple vous pourrez de nouveau utiliser la bouche foreach sans peur ou simplifier drastiquement l’écriture de certains fragment de code.

Un bref historique

Le framework .Net est une solution crée par Microsoft pour la plateforme Windows avec des versions majeurs en moyenne tous les 2 ans. C’est un ensemble d’outils composés d’une machine virtuelle, le CLR (Common Language Runtime), d’un compilateur et d’autres outils. Lorsque l’on crée un projet .Net, il faut définir la cible de compilation qui va déterminer la version du langage qu’il sera possible d’utiliser. Le langage C# 6 demandera une cible .Net 4.6 par exemple !

Le projet Mono est une recréation du framework .Net en open source, il est mis à jour très rapidement et est relativement conforme à son homologique sous Windows. Unity utilise son propre fork du projet Mono pour le scripting, cependant, jusqu’à très peu de temps, la cible était limitée à .Net 2.0.

Activer .Net 4.6 sur Unity 2017.1+

Pour activer .Net 4.6 vous devez déjà télécharger Unity 2017.1 ou supérieur, de là il faut aller dans les Player Settings via le menu File > Build Settings > Configuration

Il faudra redémarrer Unity pour que le changement soit actif. L’activation de .Net 4.6 ne doit rien changer sur l’exécution de vos scripts, le comportement ne change pas. Au pire vous ne verrez aucune différence et au mieux vous noterez une amélioration des performances !

Les nouveautés du langage C#

Je vais vous lister ici les nouveautés qui me semblent important de partager. Evidemment je serais loin d’être exhaustif et vous inviterai à étudier les liens fournis pour plus d’informations.

C# 4.0 – 2010

Si vous avez utilisé XNA, vous devez surement vous rappeler du framework .Net 4.0, car il marquait le passage à la version 4.0.

Le mot clé dynamic

dynamic i = 10;

dynamic settings = data.GetPlayerSettings();
Debug.Log(settings.FogEnabled);

Bien qu’il soit pratique dans certains cas, je ne vous recommande pas d’utiliser ce mot clé. Pour ceux qui ont fait du Visual Basic, c’est la même chose que le mot clé Variant. Le mot clé dynamic va créer une variable dont le type sera défini pendant l’exécution du programme, c’est un peu comme utiliser var mais après la compilation !

Les paramètres nommés

public static void SetPlayerInfo(string name, int age = 32)
{
    Console.WriteLine("I'm {0} and I've {1}", name, age);
}

SetPlayerInfo("Yann", 32);
SetPlayerInfo(name: "Yann", age: 32);
SetPlayerInfo(age: 32, name: "Yann");

En plus des paramètres par défaut, il est possible d’utiliser directement le nom d’un paramètre suivi de sa valeur, et le tout dans l’ordre de votre choix !

Pour finir voici un lien avec liste complète des nouveautés de cette version.

C# 5.0 – 2012

Proposé à la sortie de Windows 8.0, le framework .Net 4.5 amenait avec lui une petite révolution, de la programmation asynchrone comme si c’était synchrone !

Les mots clé async & await

private async void GetNetworkScores()
{
  var client = new WebClient();
  var result = await client.DownloadStringTaskAsync(new Uri("http://your-webservice.com"));
  Console.WriteLine(result)
}

Ajouter le mot clé async devant le type de retour d’une fonction transforme cette dernière en fonction asynchrone. La première ligne est synchrone, on crée un objet WebClient et c’est tout. La deuxième ligne est plus intéressante car on ajoute le mot clé await avant l’appel de la fonction. D’ailleurs la fonction DownloadStringTaskAsync est en réalité une tâche, car le mot clé async ne s’utilise qu’avec des tâches. L’appel à Console.WriteLine ne sera fait qu’une fois la tâche DownloadStringTaskAsync terminée. L’avantage ici est que vous écrivez votre code de manière séquentielle, sans ajouter de callback.

async Task<int> CalculateScoreAsync()
{ 
    var score = 0;
    
    // A lot of calculs here...

    return score;
}

Dans ce nouvel exemple on crée une tâche simple dont le but est de calculer un score. On image que le calcul de ce score prend beaucoup de temps, donc pour ne pas bloquer le jeu, on fait ça en parallèle. L’appel à cette tâche se ferait de la manière suivante.

var score = await CalculateScoreAsync();
scoreText.text = score + " points";

Facile et efficace ! On peut d’ailleurs faire l’analogie avec les coroutines d’Unity qui fonctionnent de manière similaire.

Là encore voici un lien avec la liste complète des nouveautés.

C# 6.0 – 2014

Nous arrivons enfin en 2014, à la sortie du framework .net 4.6 ainsi qu’à la version 6 de ce bon vieux C#. Sachez que cette version apporte beaucoup de sucre syntaxique, vous permettant d’alléger votre code de manière assez significative !

Les interpolations de chaîne de caractères

var s = $"Hello my name is {name} and I've {GetAge("Yann")}.";
var s2 = $"1 + 2 = {1 + 2}";

Fini les String.concatet autres additions de string.. Evidemment pensez à utiliser un StringBuildersi vous devez travailler avec beaucoup de chaines différentes.

Les propriétés

public int Score { get; set; } = 42;
public int Score { get; } = 42;

Vous pouvez désormais initialiser les propriétés hors constructeur !

Les imports statiques

using static System.Math;

var x = 3.0;
var y = 4.0;
var distance = Sqrt(x * x + y * y);

Je pense que ça se passe de commentaire, le fait d’avoir utiliser le mot clé static lors de l’import permet de ne plus appeler la classe qui contient la fonction Sqrt.

Fonction inline

public int Add(int x, int y) => x + y;
public int Score => _score;
public string Name => "Yannick";

Je dois bien avouer que cette nouveauté est une de mes préférés ! Vous connaissez déjà ce genre d’écriture pour les fonctions lambda, mais là c’est différent. En effet la partie à droite de la flèche correspond à la valeur renvoyée. Dites vous que la flèche est un alias à { return votreValeur; }

Filtre d’exception

try
{
    using (var stream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write))
        DoSomethingWith(stream);
}
catch(IOException ex) if (ex.HResult == 0x80070020)
{
    // File is in use by another process
}
catch(IOException ex) if (ex.HResult == 0x80070035)
{
    // Network path was not found
}
catch(Exception ex)
{
    // Oups..
}

Il est désormais possible de filtrer les exceptions, là encore ça ne va pas avoir d’intérêt chez tout le monde, mais c’est une fonctionnalité qui s’avère somme toute assez pratique.

Vous vous en doutez, voici un lien avec toutes les nouveautés de .Net 4.6 😉

Conclusion

Nous n’avons pas fait le tour de toutes les nouveautés entre C# 2.0 et C# 6.0 mais vous avez déjà un bon ensemble de ce que vous pouvez faire pour améliorer la qualité d’écriture de votre code. De même le passage à la version 4.6 de .Net peut vous apporter un gain de performances intéressent. C’est en tout cas une promesse tenue de la part de l’équipe de développement d’Unity et c’est un réel plaisir d’écrire du code C# d’aujourd’hui 🙂