IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Apprendre les nouveautés de C# 7
Un tutoriel de Thomas Levesque

Le , par tomlev

13PARTAGES

5  0 
Bonjour,

Cette discussion est destinée à recevoir vos commentaires concernant l'article Les nouveautés de C# 7.

La version 7 du langage C# s’approche à grands pas, et la liste des fonctionnalités est désormais figée, il est donc temps de les passer en revue.

Une erreur dans cette actualité ? Signalez-nous-la !

Avatar de tomlev
Rédacteur/Modérateur https://www.developpez.com
Le 02/12/2016 à 20:13
Citation Envoyé par ijk-ref Voir le message
Ne trouverais-tu pas intéressant une rubrique Roslyn sur ce Forum ? Histoire de parler entre nous avant d'une implémentation possible et peut être mieux délimiter nos idées. Penses-tu que cela intéresserait d'autres que nous ?
A mon avis c'est pas très utile. Toutes les discussions sur le design du langage se passent sur GitHub, je vois pas trop l'intérêt d'en discuter dans notre coin.

Citation Envoyé par ijk-ref Voir le message
Parce que franchement j'ai souvenir d'avoir émis il y a quelques années l'intérêt d'un "(Type1 x, Type 2) f(Type3 z, Type4 w)" qui fut noyé par des intervenants expliquant sa non-pertinence plutôt qu'autre chose.
Oui je vois ce que tu veux dire, mais dans ce que j'ai vu, une idée est rarement rejetée sans une bonne raison. Après il faut voir aussi qu'il y a plein de features qui seraient intéressantes, mais on peut pas tout faire, et certaines sont plus prioritaires que d'autres (en fonction de la demande, de la popularité de l'idée, de la vision du comité de design du langage, etc). En plus, il faut faire gaffe à pas partir dans tous les sens, le langage doit garder une certaine cohérence, sinon ça va finir par ressembler à C++ (qui selon moi est à la base un excellent langage, mais qui est devenu au fil des années tellement compliqué que je comprends plus rien quand je lis du code C++ moderne)
1  0 
Avatar de WaterTwelve21
Membre confirmé https://www.developpez.com
Le 24/11/2016 à 10:10
Je trouve l'arrivée des fonctions locales et surtout le renouveau des tuples très intéressants ! . A peine C#6 arrivée que voila C#7 ( C#8 c'est pour l'an prochain ? ) , les entreprises suivent t-elles le rythme ?
En tout cas c'est bien de voir l’engouement qu'il y a pour l'amélioration du langage ...
0  0 
Avatar de Pol63
Expert éminent sénior https://www.developpez.com
Le 24/11/2016 à 12:26
les fonctions locales je reste sceptique
les tuples c'est une très bonne chose selon moi, fini les ref pour retourner un booléen et un string ^^
les variables out j'aime bien aussi, avoir une ligne de code pour rien du genre int i c'est toujours une ligne de trop
les littéraux avec le _ c'est plutot pas mal quand on ne manipule pas souvent de l'hexa ou du binaire, j'imagine que quand c'est le cas ca se lit bien sans

sans opinion sur le reste
j'irais donc dans le sens que ce sont des évolutions assez mineures, mais c'est surtout parce que valuetype je ne suis pas près de l'utiliser les structures par références il faudrait que je relise plusieurs fois avant de comprendre

Citation Envoyé par WaterTwelve21 Voir le message
les entreprises suivent t-elles le rythme ?
autre débat, auquel j'aurais tendance à dire "clairement non"
il y en a encore sur vs 2008 ou 2010, même des boites qui peuvent se le permettre (abo msdn par exemple) ne font pas forcément de migration
surtout parce qu'il y a peu de gens qui doivent s'intéresser aux changements d'un langages et lire ce genre de page
il faut aimer la technique et l'optimisation (de perf ou de qualité/quantité de code) pour avoir envie d'utiliser des nouvelle fonctionnalités
0  0 
Avatar de tomlev
Rédacteur/Modérateur https://www.developpez.com
Le 25/11/2016 à 0:56
Citation Envoyé par WaterTwelve21  Voir le message
les entreprises suivent t-elles le rythme ?

Ça dépend lesquelles... Dans ma boite on a adopté VS2015 et C# 6 très vite après leur sortie, du moins dans mon équipe. En fait, je pense que jusqu'ici, l'adoption des nouvelles versions du langage a été freinée par la nécessité d'acheter une nouvelle version de Visual Studio à chaque fois ; mais j'ai cru comprendre qu'il était prévu que ça change. C# évolue de plus en plus vite, et je ne pense pas que MS pourra continuer à sortir une nouvelle version de VS pour chaque nouvelle version du langage.

Il est déjà possible, via ce package NuGet, d'utiliser la dernière version du compilateur dans une version plus ancienne de Visual Studio. Par contre, vu que l'IDE lui-même ne supporte pas les nouvelles features, il y aura plein d'erreurs affichées au niveau de l'éditeur, même si ça compile... ce qui réduit un peu l'intérêt.

Citation Envoyé par Pol63  Voir le message
les fonctions locales je reste sceptique

Disons que ça évite les fonctions "helper" qui traînent un peu n'importe où dans le code, qui au fil des modifications se retrouvent loin de la méthode qui les utilise, etc. Ça permet d'avoir un code mieux organisé. Et puis les fonctions locales ont l'avantage, par rapport à des fonctions normales, de pouvoir accéder aux variables et paramètres de la méthode où elles sont déclarées.

Pour moi un des cas où c'est utile est la validation des arguments pour un itérateur ou une méthode asynchrone. En effet, un itérateur est "lazy", c'est à dire que le corps de la méthode ne commence à s'exécuter que quand on commence à énumérer le résultat, et non lors de l'appel de la méthode. Si bien que ce code ne donne pas le résultat voulu :

Code C# : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void Test() 
{ 
    var enumerable = Repeat("test", -1); // Pas d'erreur 
    using (var enumerator = enumerable.GetEnumerator()) // Toujours pas d'erreur 
    { 
        enumerator.MoveNext(); // Erreur ici 
    } 
} 
  
IEnumerable<T> Repeat<T>(T item, int count) 
{ 
    if (count < 0) 
        throw new ArgumentOutOfRangeException("count must be positive"); 
  
    for (int i = 0; i < count; i++) 
    { 
        yield return item; 
    } 
}

Pour que les arguments soient validés immédiatement lors de l'appel, il faut écrire la méthode Repeat comme ceci :

Code C# : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
IEnumerable<T> Repeat<T>(T item, int count) 
{ 
    if (count < 0) 
        throw new ArgumentOutOfRangeException("count must be positive"); 
    return RepeatIterator(item, count); 
} 
  
IEnumerable<T> RepeatIterator<T>(T item, int count) 
{ 
    for (int i = 0; i < count; i++) 
    { 
        yield return item; 
    } 
}

Ce qui n'est pas super pratique... Avec les fonctions locales, on peut faire ça :

Code C# : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
IEnumerable<T> Repeat<T>(T item, int count) 
{ 
    if (count < 0) 
        throw new ArgumentOutOfRangeException("count must be positive"); 
  
    IEnumerable<T> Iterator() 
    { 
        for (int i = 0; i < count; i++) 
        { 
            yield return item; 
        } 
    } 
  
    return Iterator(); 
}
0  0 
Avatar de ijk-ref
Membre éclairé https://www.developpez.com
Le 30/11/2016 à 3:52
Je suis très étonné par le choix de "Deconstruct"
Code C# : Sélectionner tout
1
2
3
4
5
public void Deconstruct(out double x, out double y) 
{ 
    x = this.X; 
    y = this.Y; 
}

Je comprends qu'en interne ils veuillent se reposer sur du C# "ancien" mais pour l'utilisateur final d'aujourd'hui le but des nouveaux "tuples" n'est-il pas justement d'éviter au maximum l'utilisation peu pratique et archaïque de "out" ?

L'utiliser sous cette forme me semblerait plus judicieuse :
Code C# : Sélectionner tout
public (double x, double y) Deconstruct() => (this.X, this.Y);

Ensuite la possibilité de déclarer directement une variable "out" est une bonne chose... mais pour moi elle repose toujours sur le mauvais choix de continuer à utiliser "out"

AMHA une autre direction comme avec un mécanisme d'"exception light" - quand la gestion d'exception classique n'est pas obligatoire ou trop lourde.

En introduisant par exemple deux nouveaux mots clés, un permettant une sortie incorrecte (sans lancer d'exception) d'une méthode et un autre pour la tester :
Code C# : Sélectionner tout
1
2
3
4
if (try int i = int.ParseLight(s)) 
{ 
    Console.WriteLine($"La chaine représente un entier de valeur {i}"); 
}

Et comme je réfléchis en même temps que j'écris... je pense même qu'il serait possible de transformer les Parses avec exceptions classiques pour qu'ils fonctionnent... classiquement et aussi dans un mode light se suffisant d'un simple test booléen comme le code au-dessus.

Sinon avec C# 7 on doit pouvoir écrire cela (bon c'est un peu plus verbeux mais adieux les "out" ):
Code C# : Sélectionner tout
1
2
3
4
if (!((bool error, int i) = int.ParseLight2(s)).error) 
{ 
    Console.WriteLine($"La chaine représente un entier de valeur {i}"); 
}

Autrement dans ton switch Pattern matching ça fonctionnerait un "goto Circle c when c.Radius < 5" ?

Sinon n'y aurait-il pas une petite faute dans ton exemple sur la généralisation du type de retour des méthodes asynchrones ? AMHA la variable "price" en attente n'est pas déclarée puisqu'avant elle est interne au if.
0  0 
Avatar de tomlev
Rédacteur/Modérateur https://www.developpez.com
Le 30/11/2016 à 14:05
Citation Envoyé par ijk-ref  Voir le message
Je suis très étonné par le choix de "Deconstruct"
Code C# : Sélectionner tout
1
2
3
4
5
public void Deconstruct(out double x, out double y) 
{ 
    x = this.X; 
    y = this.Y; 
}

Je comprends qu'en interne ils veuillent se reposer sur du C# "ancien" mais pour l'utilisateur final d'aujourd'hui le but des nouveaux "tuples" n'est-il pas justement d'éviter au maximum l'utilisation peu pratique et archaïque de "out" ?

C'est juste au niveau de la déclaration ; au niveau de l'utilisation, tu n'as pas besoin de out. Et de toute façon c'est juste si tu veux ajouter à une classe la possibilité de la déconstruire, pour les tuples tu n'as rien à faire, c'est déjà fait.

Citation Envoyé par ijk-ref  Voir le message
L'utiliser sous cette forme me semblerait plus judicieuse :
Code C# : Sélectionner tout
public (double x, double y) Deconstruct() => (this.X, this.Y);

C'était ma première réaction, mais en fait il y a une bonne raison : avec la syntaxe choisie, tu peux avoir plusieurs méthodes Deconstruct, avec des signatures différentes :

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
public void Deconstruct(out double x, out double y) 
{ 
    x = this.X; 
    y = this.Y; 
} 
 
public void Deconstruct(out double x, out double y, out double z) 
{ 
    x = this.X; 
    y = this.Y; 
    z = this.Z; 
}
Avec ce que tu proposes, ce ne serait pas possible, vu que tu ne peux pas avoir deux méthodes qui ne diffèrent que par le type de retour.

Citation Envoyé par ijk-ref  Voir le message
AMHA une autre direction comme avec un mécanisme d'"exception light" - quand la gestion d'exception classique n'est pas obligatoire ou trop lourde.

En introduisant par exemple deux nouveaux mots clés, un permettant une sortie incorrecte (sans lancer d'exception) d'une méthode et un autre pour la tester :
Code C# : Sélectionner tout
1
2
3
4
if (try int i = int.ParseLight(s)) 
{ 
    Console.WriteLine($"La chaine représente un entier de valeur {i}"); 
}

J'aime bien le principe... tu peux le proposer sur le GitHub Roslyn

Citation Envoyé par ijk-ref  Voir le message
Et comme je réfléchis en même temps que j'écris... je pense même qu'il serait possible de transformer les Parses avec exceptions classiques pour qu'ils fonctionnent... classiquement et aussi dans un mode light se suffisant d'un simple test booléen comme le code au-dessus.

Le problème des méthodes Parse qui renvoient des exceptions, c'est que les exceptions ne sont pas seulement lourdes en terme de syntaxe, mais aussi en terme de performance. Lancer et catcher une exception, ça coûte cher...

Citation Envoyé par ijk-ref  Voir le message
Sinon avec C# 7 on doit pouvoir écrire cela (bon c'est un peu plus verbeux mais adieux les "out" ):
Code C# : Sélectionner tout
1
2
3
4
if (!((bool error, int i) = int.ParseLight2(s)).error) 
{ 
    Console.WriteLine($"La chaine représente un entier de valeur {i}"); 
}

Oula, pas sûr que ce soit plus lisible... Ce qui serait plus intéressant, c'est une méthode TryParse qui renvoie un Nullable<int>, ça permettrait d'utiliser le pattern matching pour faire ça :

Code : Sélectionner tout
1
2
3
4
if (int.TryParse(s) is int i) 
{ 
    ... 
}
Citation Envoyé par ijk-ref  Voir le message
Autrement dans ton switch Pattern matching ça fonctionnerait un "goto Circle c when c.Radius < 5" ?

Non, ça marche pas. Tu peux toujours faire un goto vers un case <Constante>, mais pas vers un case <Type>.

Citation Envoyé par ijk-ref  Voir le message
Sinon n'y aurait-il pas une petite faute dans ton exemple sur la généralisation du type de retour des méthodes asynchrones ? AMHA la variable "price" en attente n'est pas déclarée puisqu'avant elle est interne au if.

Non non, c'est correct. Pendant la phase de design il y a eu pas mal de discussions sur le scope d'une variable déclarée comme ça, mais la rendre interne au if posait trop de problèmes. Exemple type de pourquoi c'est problématique :

Code : Sélectionner tout
1
2
3
4
5
6
7
8
if (!int.TryParse(s, out int i)) 
{ 
    // i est défini, mais ça valeur n'a pas de sens puisque TryParse a échoué 
} 
else 
{ 
    // TryParse a réussi, mais i n'est pas défini 
}
Donc au final le scope de la variable est le scope parent du if.
0  0 
Avatar de ijk-ref
Membre éclairé https://www.developpez.com
Le 01/12/2016 à 17:05
Citation Envoyé par tomlev  Voir le message
C'était ma première réaction, mais en fait il y a une bonne raison : avec la syntaxe choisie, tu peux avoir plusieurs méthodes Deconstruct, avec des signatures différentes

Ah oui merci !

Citation Envoyé par tomlev  Voir le message
Le problème des méthodes Parse qui renvoient des exceptions, c'est que les exceptions ne sont pas seulement lourdes en terme de syntaxe, mais aussi en terme de performance. Lancer et catcher une exception, ça coûte cher...

Mais c'est exactement ce que je sous entendais : lourdes dans tous les sens

C'est pourquoi j'imagine qu'en interne les méthodes traitées avec "exceptions lights" auraient un code optimisé et différent. Leurs exceptions retirées et remplacées pour une sortie de fonction classique... une seconde sortie comme je l'explique ici.

J'ai un peu modifié mon "try" après tes précisions sur le scope des variables "out" pour le rendre plus général par exemple si l'on souhaite sortir un code d'erreur ou n'importe quoi - qui n'a absolument pas besoin d'être de type "Exception".

Code C# : Sélectionner tout
1
2
3
4
5
6
7
try int i = int.Parse(s) otherwise i = 0; 
  
try double j = double.Parse(s) otherwise return; 
  
try int k = int.Parse(s) otherwise Console.WriteLine("impossible à parser"); // Erreur à la compilation car 'k' n'est pas toujours défini (pour la suite du code) 
  
try DX.DrawTriangles(vertices) otherwise(int error) { Console.WriteLine("Erreur dans le code n°" + error);  return; }
Citation Envoyé par tomlev  Voir le message
J'aime bien le principe... tu peux le proposer sur le GitHub Roslyn

J'aimerai bien. C'est dommage de rencontrer ici si peu de personnes le maîtrisant (dont moi). Et je ne trouves vraiment pas beaucoup d'exemples varié sur le sujet.

Citation Envoyé par tomlev  Voir le message
Non, ça marche pas. Tu peux toujours faire un goto vers un case <Constante>, mais pas vers un case <Type>.

Je m'y attendais et même le souhaitais

Ils auraient mieux fait de l'implémenter loin de ce "switch" sans les ":" et "break".
0  0 
Avatar de tomlev
Rédacteur/Modérateur https://www.developpez.com
Le 02/12/2016 à 1:45
Citation Envoyé par ijk-ref Voir le message
J'aimerai bien. C'est dommage de rencontrer ici si peu de personnes le maîtrisant (dont moi). Et je ne trouves vraiment pas beaucoup d'exemples varié sur le sujet.
Maîtriser quoi ? Je suggérais juste de proposer l'idée, pas de l'implémenter (c'est certainement pas simple à implémenter, et même si tu veux le faire, ça sert à rien de se lancer dans un tâche aussi grosse avant de s'être mis d'accord sur le design exact).

Citation Envoyé par ijk-ref Voir le message
Ils auraient mieux fait de l'implémenter loin de ce "switch" sans les ":" et "break".
Peut-être... ça a été envisagé d'ailleurs. Je crois qu'ils ont préféré garder le switch parce que les gens y sont habitués. Personnellement je trouve que switch est un des trucs les plus horribles de C#. Il a été hérité de C presque tel quel (en ajoutant juste l'interdiction du fallthrough pour le rendre un peu plus sûr), avec les mêmes défauts de design. Ce qui m'agace le plus c'est le fait qu'une variable déclarée dans un case est en fait dans le scope du switch, ce qui fait qu'on ne peut pas déclarer une autre variable du même nom dans un autre case.
0  0 
Avatar de ijk-ref
Membre éclairé https://www.developpez.com
Le 02/12/2016 à 8:41
Citation Envoyé par tomlev Voir le message
Maîtriser quoi ? Je suggérais juste de proposer l'idée, pas de l'implémenter (c'est certainement pas simple à implémenter, et même si tu veux le faire, ça sert à rien de se lancer dans un tâche aussi grosse avant de s'être mis d'accord sur le design exact)..
Ah oui j'étais parti... loin devant

Ne trouverais-tu pas intéressant une rubrique Roslyn sur ce Forum ? Histoire de parler entre nous avant d'une implémentation possible et peut être mieux délimiter nos idées. Penses-tu que cela intéresserait d'autres que nous ?

Parce que franchement j'ai souvenir d'avoir émis il y a quelques années l'intérêt d'un "(Type1 x, Type 2) f(Type3 z, Type4 w)" qui fut noyé par des intervenants expliquant sa non-pertinence plutôt qu'autre chose.

Citation Envoyé par tomlev Voir le message
Peut-être... ça a été envisagé d'ailleurs. Je crois qu'ils ont préféré garder le switch parce que les gens y sont habitués. Personnellement je trouve que switch est un des trucs les plus horribles de C#. Il a été hérité de C presque tel quel (en ajoutant juste l'interdiction du fallthrough pour le rendre un peu plus sûr), avec les mêmes défauts de design. Ce qui m'agace le plus c'est le fait qu'une variable déclarée dans un case est en fait dans le scope du switch, ce qui fait qu'on ne peut pas déclarer une autre variable du même nom dans un autre case.
Pareil ce "switch" me donne envie de vomir
0  0 
Avatar de Pol63
Expert éminent sénior https://www.developpez.com
Le 02/12/2016 à 21:01
Citation Envoyé par tomlev Voir le message
A mon avis c'est pas très utile. Toutes les discussions sur le design du langage se passent sur GitHub, je vois pas trop l'intérêt d'en discuter dans notre coin.
surtout à 2 ^^
(déjà qu'on est que 3 à parler des nouveautés ...)

Citation Envoyé par tomlev Voir le message
En plus, il faut faire gaffe à pas partir dans tous les sens, le langage doit garder une certaine cohérence, sinon ça va finir par ressembler à C++ (qui selon moi est à la base un excellent langage, mais qui est devenu au fil des années tellement compliqué que je comprends plus rien quand je lis du code C++ moderne)
oui, j'ai cru comprendre qu'il y a eut plusieurs grosses évolutions avec des différences fondamentales, et qu'on peut mixer le tout pour noyer encore plus ^^
0  0