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 !

Qu'est-ce que .NET, et pourquoi le choisir ?
Par Microsoft .NET team

Le , par Sandra Coret

763PARTAGES

6  1 
.NET a beaucoup changé depuis son lancement, un projet open-source et multiplateforme en pleine évolution. La plate-forme a été repensée et affinée, avec l'ajout de nouvelles fonctionnalités de bas niveau conçues pour la performance et la sécurité, associées à des fonctionnalités de haut niveau axées sur la productivité. Span<T>, les intrinsèques du matériel et les types de référence nullables en sont des exemples. Une nouvelle série de blogs sur les " points de conception .NET " a été lancée pour explorer les principes fondamentaux et les choix de conception qui définissent la plate-forme .NET actuelle, ainsi que les avantages qu'ils présentent pour le code que vous écrivez actuellement.

Ce premier article de la série donne un aperçu général des piliers et du point de conception de la plate-forme. Il décrit "ce que vous obtenez" à un niveau fondamental lorsque vous choisissez .NET et est destiné à être un cadre suffisant et axé sur les faits que vous pouvez utiliser pour décrire la plate-forme à d'autres. Des articles ultérieurs traiteront plus en détail de ces mêmes sujets, car cet article ne rend pas justice à toutes ces caractéristiques. Cet article ne décrit pas les outils, comme Visual Studio, ni les bibliothèques de niveau supérieur et les modèles d'application comme ceux fournis par ASP.NET Core.

Le " .NET " dont nous parlons est le .NET Core moderne. Au cas où vous l'auriez manqué, nous avons lancé ce projet en 2014 en tant que projet open source sur GitHub. Il fonctionne sous Linux, macOS et Windows sur Arm64, x64 et d'autres architectures de puces. Il est disponible dans un tas de distros Linux. Il conserve une grande partie de la compatibilité avec .NET Framework, mais constitue une nouvelle direction et un nouveau produit.

Avant d'entrer dans les détails, il convient de parler de l'utilisation de .NET. Il est utilisé par des millions de développeurs pour créer des applications cloud, client et autres sur de multiples systèmes d'exploitation et architectures de puces. Il est également exécuté dans certains endroits bien connus, comme Azure, StackOverflow et Unity. Il est courant de trouver .NET utilisé dans des entreprises de toutes tailles, mais particulièrement dans les plus grandes. Dans de nombreux endroits, c'est une bonne technologie à connaître pour obtenir un emploi.

Voir la réaction de la communauté à cet article : Réflexions sur "Qu'est-ce que .NET et pourquoi le choisir ?

Point de conception .NET

La plate-forme .NET est synonyme de productivité, de performance, de sécurité et de fiabilité. L'équilibre que .NET établit entre ces valeurs est ce qui le rend attrayant.
Le point de conception de .NET peut se résumer à être efficace et efficient à la fois dans le domaine sûr (où tout est productif) et dans le domaine non sûr (où une fonctionnalité énorme existe). .NET est peut-être l'environnement géré qui possède le plus de fonctionnalités intégrées, tout en offrant le coût le plus bas pour l'interopérabilité avec le monde extérieur, sans aucun compromis entre les deux. En fait, de nombreuses fonctionnalités exploitent cette séparation transparente, en construisant des API gérées sûres sur la puissance et les capacités brutes du système d'exploitation et du processeur sous-jacents.

Nous pouvons nous étendre un peu plus sur le point de la conception :

  • La productivité est le principal critère de conception pour l'exécution, les bibliothèques, le langage et les outils.
  • Le code sûr est le principal modèle de calcul, tandis que le code non sûr permet des optimisations manuelles supplémentaires
  • Le code statique et le code dynamique sont tous deux pris en charge, ce qui permet un large éventail de scénarios distincts.
  • L'interopérabilité du code natif et les éléments matériels intrinsèques sont peu coûteux et de haute fidélité (accès brut à l'API et aux instructions).
  • Le code est portable sur toutes les plates-formes (système d'exploitation, architecture de puce), tandis que le ciblage de la plate-forme permet la spécialisation et l'optimisation.
  • L'adaptabilité entre les domaines de programmation (cloud, client, jeux) est rendue possible par des implémentations spécialisées du modèle de programmation universel.
  • Les normes industrielles telles que OpenTelemetry et gRPC sont préférées aux solutions sur mesure.


Le moteur d'exécution, les bibliothèques et les langages sont les piliers de la pile .NET. Les composants de niveau supérieur, tels que les outils .NET et les piles d'applications comme ASP.NET Core, reposent sur ces piliers. Les piliers ont une relation symbiotique, ayant été conçus et construits ensemble par un seul groupe (les employés de Microsoft et la communauté open source), où les individus travaillent sur et informent plusieurs de ces composants.

C# est orienté objet et le runtime supporte l'orientation objet. C# nécessite un ramasse-miettes et le runtime fournit un ramasse-miettes de traçage. En fait, il serait impossible de porter C# (dans sa forme complète) sur un système sans ramasse-miettes. Les bibliothèques (et aussi les piles d'applications) transforment ces capacités en concepts et modèles d'objets qui permettent aux développeurs d'écrire des algorithmes de manière productive dans des flux de travail intuitifs.

C# est un langage de programmation moderne, sûr et polyvalent, qui s'étend des fonctionnalités de haut niveau telles que les enregistrements orientés données aux fonctionnalités de bas niveau telles que les pointeurs de fonction. Il offre le typage statique et la sécurité des types et de la mémoire comme capacités de base, ce qui améliore simultanément la productivité des développeurs et la sécurité du code. Le compilateur C# est également extensible et prend en charge un modèle de plug-in qui permet aux développeurs de compléter le système par des diagnostics supplémentaires et la génération de code à la compilation.

Un certain nombre de fonctionnalités de C# ont influencé ou ont été influencées par des langages de programmation de pointe. Par exemple, C# a été le premier langage grand public à introduire async et await. En même temps, C# emprunte des concepts introduits pour la première fois dans d'autres langages de programmation, par exemple en adoptant des approches fonctionnelles telles que le filtrage et les constructeurs primaires.

Les bibliothèques de base exposent des milliers de types, dont beaucoup s'intègrent au langage C# et l'alimentent. Par exemple, le foreach de C# permet d'énumérer des collections arbitraires, avec des optimisations basées sur des motifs qui permettent de traiter simplement et efficacement des collections comme List<T>. La gestion des ressources peut être laissée au ramasse-miettes, mais un nettoyage rapide est possible grâce à IDisposable et au support direct du langage dans using.

L'interpolation de chaînes en C# est à la fois expressive et efficace, intégrée et alimentée par des implémentations dans les types de base de la bibliothèque comme string, StringBuilder et Span<T>. Enfin, les fonctionnalités de requêtes intégrées au langage (LINQ) sont alimentées par des centaines de routines de traitement de séquences dans les bibliothèques, comme Where, Select et GroupBy, avec une conception extensible et des implémentations qui prennent en charge les sources de données en mémoire et distantes. La liste est longue et ce qui est intégré directement dans le langage ne fait qu'effleurer la surface des fonctionnalités exposées dans le cadre des bibliothèques .NET de base, de la compression à la cryptographie en passant par les expressions régulières. Une pile réseau complète constitue un domaine à part entière, allant des sockets à HTTP/3. De même, les bibliothèques prennent en charge le traitement d'une myriade de formats et de langages tels que JSON, XML et tar.

Le moteur d'exécution .NET était initialement appelé "Common Language Runtime (CLR)". Il continue à prendre en charge de nombreux langages, certains étant maintenus par Microsoft (par exemple C#, F#, Visual Basic, C++/CLI et PowerShell) et d'autres par d'autres organisations (par exemple Cobol, Java, PHP, Python, Scheme). De nombreuses améliorations sont agnostiques du point de vue du langage, ce qui permet d'améliorer la situation.

Ensuite, nous allons examiner les diverses caractéristiques de la plate-forme qu'ils offrent ensemble. Nous pourrions détailler chacun de ces composants séparément, mais vous verrez rapidement qu'ils coopèrent pour répondre aux critères de conception de .NET. Commençons par le système de types.

Système de types

Le système de types de .NET offre un large éventail de possibilités, répondant à peu près également aux besoins de sécurité, de descriptivité, de dynamisme et d'interopérabilité native.

Avant tout, le système de types permet un modèle de programmation orienté objet. Il inclut les types, l'héritage (classe de base unique), les interfaces (y compris les implémentations de méthodes par défaut) et la répartition des méthodes virtuelles afin de fournir un comportement raisonnable pour toutes les couches de types que l'orientation objet permet.

Les génériques sont une fonctionnalité omniprésente qui permet de spécialiser les classes en un ou plusieurs types. Par exemple, List<T> est une classe générique ouverte, tandis que les instanciations comme List<string> et List<int> évitent d'avoir à créer des classes distinctes ListOfString et ListOfInt ou de s'appuyer sur des objets et des castings comme c'était le cas avec ArrayList. Les génériques permettent également de créer des systèmes utiles à travers des types disparates (et de réduire le besoin de beaucoup de code), comme avec Generic Math.

Les délégués et les lambdas permettent de passer des méthodes en tant que données, ce qui facilite l'intégration de code externe dans un flux d'opérations appartenant à un autre système. Ils constituent une sorte de "code colle" et leurs signatures sont souvent génériques pour permettre une large utilisation.

Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
app.MapGet("/Product/{id}", async (int id) =>
{
    if (await IsProductIdValid(id))
    {
        return await GetProductDetails(id);
    }

    return Products.InvalidProduct;
});
Cette utilisation de lambdas fait partie des API minimales d'ASP.NET Core. Elle permet de fournir une implémentation de point de terminaison directement au système de routage. Dans les versions plus récentes, ASP.NET Core fait un usage plus étendu du système de types.

Les types de valeurs et les blocs de mémoire alloués par pile offrent un contrôle plus direct et de bas niveau sur les données et une interopérabilité avec la plate-forme native, contrairement aux types gérés par GC de .NET. La plupart des types primitifs de .NET, comme les types entiers, sont des types de valeur, et les utilisateurs peuvent définir leurs propres types avec une sémantique similaire.

Les types de valeur sont entièrement pris en charge par le système générique de .NET, ce qui signifie que les types génériques comme List<T> peuvent fournir des représentations mémoire plates, sans frais généraux, des collections de type valeur. En outre, les génériques .NET fournissent un code compilé spécialisé lorsque les types de valeur sont substitués, ce qui signifie que ces chemins de code génériques peuvent éviter une surcharge GC coûteuse.

Code : Sélectionner tout
1
2
3
byte magicSequence = 0b1000_0001;
Span<byte> data = stackalloc byte[128];
DuplicateSequence(data[0..4], magicSequence);
Ce code résulte en des valeurs allouées en pile. Le Span<byte> est une version sûre et plus riche de ce qui serait autrement un octet*, fournissant une valeur de longueur (avec vérification des limites) et un découpage pratique du span.

Les types et variables Ref sont une sorte de mini-modèle de programmation qui offre des abstractions de plus bas niveau et plus légères sur les données du système de types. Cela inclut Span<T>. Ce modèle de programmation n'est pas d'usage général et comporte des restrictions importantes pour maintenir la sécurité.

Code : Sélectionner tout
internal readonly ref T _reference;
Cette utilisation de ref entraîne la copie d'un pointeur vers le stockage sous-jacent plutôt que la copie des données référencées par ce pointeur. Les types de valeurs sont "copiés par valeur" par défaut. ref fournit un comportement de "copie par référence", qui peut fournir des avantages significatifs en termes de performances.

Gestion automatique de la mémoire

Le moteur d'exécution .NET assure une gestion automatique de la mémoire par le biais d'un ramasse-miettes (Garbage Collector). Pour tout langage, le modèle de gestion de la mémoire est probablement sa caractéristique la plus déterminante. Ceci est vrai pour les langages .NET.

Les bogues de corruption de tas sont notoirement difficiles à déboguer. Il n'est pas rare que les ingénieurs passent des semaines, voire des mois, à les rechercher. De nombreux langages utilisent un ramasse-miettes comme moyen convivial d'éliminer ces bogues, car le GC garantit la durée de vie correcte des objets. En général, les GC libèrent la mémoire par lots pour fonctionner efficacement. Cela entraîne des pauses qui peuvent ne pas convenir si vous avez des exigences de latence très strictes, et l'utilisation de la mémoire serait plus élevée. Les GC ont tendance à avoir une meilleure localisation de la mémoire et certains sont capables de compacter le tas, ce qui le rend moins sujet à la fragmentation de la mémoire.

.NET dispose d'une GC auto-réglée et traçante. Il vise à fournir un fonctionnement "sans intervention" dans le cas général tout en offrant des options de configuration pour les charges de travail plus extrêmes. Le GC est le résultat de nombreuses années d'investissement, d'amélioration et d'apprentissage à partir de nombreux types de charges de travail.

Allocation par pointeur de bosse - les objets sont alloués en incrémentant un pointeur d'allocation de la taille nécessaire (au lieu de trouver de l'espace dans des blocs libres séparés), de sorte que les objets alloués ensemble ont tendance à rester ensemble. Et comme les objets sont souvent accédés ensemble, cela permet une meilleure localisation de la mémoire, ce qui est important pour les performances.

Collections générationnelles - il est extrêmement fréquent que la durée de vie des objets suive l'hypothèse générationnelle, c'est-à-dire qu'un objet vit très longtemps ou meurt très rapidement. Il est donc beaucoup plus efficace pour un GC de ne collecter que la mémoire occupée par des objets éphémères la plupart du temps (appelé GC éphémères), au lieu de devoir collecter tout le tas (appelé GC complets) à chaque fois qu'il s'exécute.

Compactage - la même quantité d'espace libre dans des morceaux plus grands et moins nombreux est plus utile que dans des morceaux plus petits et plus nombreux. Au cours d'une GC de compactage, les objets survivants sont déplacés ensemble afin de former de plus grands espaces libres. Ce comportement nécessite une mise en œuvre plus sophistiquée qu'un GC sans déplacement car il doit mettre à jour les références à ces objets déplacés. Le GC .NET est réglé de manière dynamique pour effectuer le compactage uniquement lorsqu'il détermine que la mémoire récupérée vaut le coût du GC. Cela signifie que les collections éphémères sont souvent compactées.

Parallèle - Le travail GC peut être exécuté sur un seul ou plusieurs threads. La version Workstation effectue le travail GC sur un seul fil d'exécution, tandis que la version Server l'effectue sur plusieurs fils d'exécution GC, ce qui permet de le terminer beaucoup plus rapidement. Le GC du serveur peut également s'accommoder d'un taux d'allocation plus élevé, car il y a plusieurs tas sur lesquels l'application peut allouer, ce qui est très bon pour le débit.

Concurrent - effectuer le travail GC pendant que les threads de l'utilisateur sont en pause - appelé Stop-The-World - rend l'implémentation plus simple mais la durée de ces pauses peut être inacceptable. .NET offre une saveur concurrente pour atténuer ce problème.

Épinglage - le GC .NET prend en charge l'épinglage des objets, qui permet une interopérabilité sans copie avec le code natif. Cette capacité permet une interopérabilité native haute performance et haute fidélité, avec une surcharge limitée pour le GC.

GC autonome - il est possible d'utiliser un GC autonome avec une implémentation différente (spécifiée via la configuration et répondant aux exigences de l'interface). Cela facilite les recherches et l'essai de nouvelles fonctionnalités.

Diagnostic - Le GC fournit des informations riches sur la mémoire et les collections, structurées d'une manière qui vous permet de corréler les données avec le reste du système. Par exemple, vous pouvez évaluer l'impact du GC sur la latence de votre queue en capturant les événements GC et en les corrélant avec d'autres événements comme les entrées/sorties pour calculer la...
La fin de cet article est réservée aux abonnés. Soutenez le Club Developpez.com en prenant un abonnement pour que nous puissions continuer à vous proposer des publications.

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

Avatar de micka132
Expert confirmé https://www.developpez.com
Le 28/02/2023 à 12:01
Citation Envoyé par drcd Voir le message
Et je cherche toujours comment faire de l'AOP de manière clean et efficace en .NET.
Peut-être qu'il faudrait plus de précision?
De base n'importe quel outil/langage/framework qui sort se veut clean et efficace !
Donc en l'état ca revient à dire que tu cherches à faire de l'AOP, et là j'ai du mal à croire que tu n'es pas trouvé.
2  0 
Avatar de micka132
Expert confirmé https://www.developpez.com
Le 01/03/2023 à 10:08
Peut-être celui-ci te semblera simple
https://medium.com/@yurexus/aspect-o...r-cb56d8f80254
Ou celui là
https://medium.com/@sddkal/aop-with-...e-97c547ba27ba

Dans un contexte asp.net MVC tu vas avoir ce qui tourne autour de ActionFilterAttribute

Plus "bas niveau" tu vas avoir Realproxy / dispatchProxy https://devblogs.microsoft.com/dotne...dispatchproxy/

Plus "complet" tu as également postsharp, Ninject avec l'interceptor et j'imagine tant d'autres !

Je pense que ton référentiel c'et AspectJ, et en jetant un œil je ne vois pas ce que tu lui trouves de "clean".
Pour moi ca me semble, comme souvent lorsqu'on aborde un outil complet, assez obscure!
2  0 
Avatar de micka132
Expert confirmé https://www.developpez.com
Le 02/03/2023 à 8:54
Citation Envoyé par drcd Voir le message
Sur tous les exemples que tu as donné, disons qu'on remplace Console.WriteLine() par un appel à un client http, on peut injecter le client http?
Dans tous les cas tu peux avoir ton propre conteneur IOC ou factory qui sera en static et donc faire appel depuis n'importe où, et donc à la place de Console.WriteLine()

Pour l'injection directement via constructeur ou paramètre, je ne sais pas, j'imagine que selon la complexité du framework ce sera possible (PostSharp peut-être).
Citation Envoyé par drcd Voir le message

Mais j'ai des doutes sur l'avenir de la maintenance de ce projet.
C'est toujours le risque lorsque l'on prend des librairies tierces, mais dans ce cas précis tu as les sources et elles ne sont pas monstrueuses si jamais il y a besoin vital d'évolution.
Sans compter que le principe même de l'AOP c'est de faire des choses à coté, sans toucher le fonctionnement. Si demain tu dois changer de framework ca devrait être totalement transparent pour le déroulement métier.
1  0 
Avatar de drcd
Membre averti https://www.developpez.com
Le 28/02/2023 à 14:16
Par exemple, comment on fait un systeme qui calcule le temps d'execution d'une fonction et qui envoie le resultat dans un systeme tierce en faisant un appel http et ayant de l'injection de dépendance?

En java, le probleme se regle avec une annotation et AspectJ. En typescript, un simple décorateur. C#, j'ai pas trouvé grand chose.
0  0 
Avatar de NitroDeath666
Membre à l'essai https://www.developpez.com
Le 24/02/2023 à 14:24
Techno efficace et lourdement supportée par Microsoft.
Permet d'adresser de nombreux besoins variés avec une seule techno, viable sur le long terme.
Loin des technos versatiles qui nous inondent, on a ici un Framework stable dans le temps qui permet de basculer d'un client lourd à appli native Android par exemple, en réutilisant une grande partie du code.
Question maintenabilité, difficile de faire mieux. gj à Microsoft, que j'ai maudis bêtement pendant une décennie
0  1 
Avatar de drcd
Membre averti https://www.developpez.com
Le 01/03/2023 à 16:19
Realproxy / dispatchProxy: Il faut ecrire pas mal de code quand meme
AspectInjector a l'air intéressant. Mais j'ai des doutes sur l'avenir de la maintenance de ce projet.
Les autres exemples ne font que des appels à Console.WriteLine() qui est une methode statique. Sur tous les exemples que tu as donné, disons qu'on remplace Console.WriteLine() par un appel à un client http, on peut injecter le client http?
0  1 
Avatar de drcd
Membre averti https://www.developpez.com
Le 28/02/2023 à 10:59
Désolé, je ne suis pas d'accord. Les autres technos n'ont pas besoin de ce genre d'articles. Et je cherche toujours comment faire de l'AOP de manière clean et efficace en .NET.
0  2