Fonctionnalités C # ou .Net à couper en supposant qu'aucune compatibilité descendante n'est nécessaire? [fermé]

18

Tout produit ou framework évolue. Il est principalement fait pour répondre aux besoins de ses utilisateurs, tirer parti de nouvelles puissances informatiques et simplement les améliorer. Parfois, l'objectif de conception principal change également avec le produit. Le framework C # ou .net ne fait pas exception. Comme nous le voyons, la 4ème version actuelle est très différente de la première. Mais la chose vient comme une barricade à cette compatibilité avec l'évolution vers l'arrière.

Dans la plupart des frameworks / produits, certaines fonctionnalités auraient été supprimées s'il n'était pas nécessaire de prendre en charge la compatibilité descendante. Selon vous, quelles sont ces fonctionnalités dans C # /. Net?

Veuillez mentionner une fonctionnalité par réponse.

Gulshan
la source
Mot-clé nouveau
Nemanja Trifunovic
4
La question n'est clairement pas constructive selon les directives, et clairement constructive sur la base des réponses fantastiques. Voter pour rouvrir.
psr
1
dommage qu'il ait fermé, peut-être qu'Eric va bloguer ça au lieu de répondre ici?
jk.

Réponses:

35

Méthodes anonymes . Je pense que tout le monde convient que la syntaxe de méthode anonyme choisie pour C # 2.0 est volumineuse et maladroite par rapport à la syntaxe lambda que nous avons ajoutée à C # 3.0. Il est profondément regrettable d'avoir deux syntaxes presque identiques pour faire la même chose.

Eric Lippert
la source
1
D'accord, les méthodes anonymes étaient super quand nous n'avions pas de lambdas ... maintenant elles sont juste redondantes.
Michael Brown
9
Il y a une particularité des méthodes anonymes qui est bien meilleure que les expressions lambda .... leur nom parfait !!
explorest
1
À ce stade, je ne me souviens même pas de la syntaxe d'une méthode anonyme en C #. Je devrais chercher si pour une raison bizarre je devais en utiliser un au lieu d'un lambda.
Kyralessa
33

Je me débarrasserais des collections non génériques. Ils sont une abomination ... et il y a trop de cas où j'utilise linq et je dois faire quelque chose comme

var customObjects = container.CustomObjects.Cast<CustomObject>();

Chaque fois que je dois faire ça, une petite partie de mon âme meurt.

Michael Brown
la source
C'est trop génial.
1
Tous les ports de .NET ne prennent pas en charge les génériques. .NET Micro en est un exemple. Peut ne pas s'appliquer si CustomObjects ne se déplacera jamais sur cette plateforme.
goodguys_activate
2
C'est l'avantage de ne pas avoir d'âme.
CaffGeek
29

vide en tant que type . Pourquoi diable est "nul" un type? Il n'a pas d'instances, il n'a pas de valeurs, vous ne pouvez pas l'utiliser comme argument de type générique, type de paramètre formel, type local, type de champ ou type de propriété. Il n'a aucune signification en tant que type; c'est plutôt un fait sur l' effet d'un appel de méthode sur la pile de la machine virtuelle. Mais la machine virtuelle n'est que cela: une machine virtuelle. La vraie machine mettra la valeur retournée dans un registre (généralement EAX sur x86) et n'affectera pas du tout la pile! Le vide en tant que type n'est qu'une mauvaise idée tout autour.

Pire: lorsqu'il est utilisé dans un type pointeur, car void*il signifie quelque chose de complètement différent de ce qu'il signifie lorsqu'il est utilisé comme type de retour. Maintenant, cela signifie "un pointeur vers un emplacement de stockage de type inconnu", ce qui n'a rien à voir avec sa signification en tant que "méthode qui ne renvoie aucune valeur".

Nous pouvons remplacer void*comme type de pointeur par IntPtr. (Et void**avec IntPtr*et ainsi de suite.) Nous pouvons remplacer void comme type de retour par "Unit", un type qui a une seule valeur, à savoir null. Une implémentation du CLR pourrait alors décider qu'un appel de fonction de type unitaire pourrait optimiser son utilisation des registres ou des piles de manière appropriée, sachant que le zéro qui est "renvoyé" peut être ignoré en toute sécurité.

Dans un tel monde , vous ne avez plus besoin de séparer Func<A, R>et les Action<T>délégués. Action<T>est juste Func<T, Unit>.

Eric Lippert
la source
4
... et Taskc'est juste un Task<Unit>. Réimplémenter les bits de bibliothèque du CTP asynchrone m'a vraiment fait souhaiter cela ...
Jon Skeet
24

L'instruction vide; . Sujette aux erreurs, presque toujours une faute de frappe, et ne vous donne aucun sens supplémentaire qui n'est pas déjà exprimé par {}.

Eric Lippert
la source
7
Sans parler de l'énorme pénalité de performance sous le JIT 64 bits </snark>.
Jesse C. Slicer
7
Une déclaration vide a une pénalité de performance? Pourquoi donc?
quentin-star du
22

Covariance dangereuse sur des tableaux de type référence . Avec la covariance typesafe activée IEnumerable<T>, au moins une partie du besoin de covariance de tableau a disparu. (Si nous avions une interface de liste en lecture seule covariante, nous n'en aurions pas du tout besoin.)

Eric Lippert
la source
J'allais absolument écrire ceci quand j'ai vu le titre de la question - vous m'avez battu dessus :(
Chris Smith
1
La possibilité de recevoir une référence de tableau covariante et d'écrire en toute sécurité dans les références de tableau qui ont été lues est utile. S'il est IList<T>hérité de IReadableList<out T>et non générique IPemutable, il pourrait prendre en charge des choses comme le tri, mais les tableaux le prennent en charge plus facilement.
supercat
14

L'opérateur unaire plus . Opérateur le moins utile de tous les temps. Si nous n'avions pas à le garder pour la compatibilité ascendante, je le retirerais en un clin d'œil. Qui utilise cette chose, n'importe qui?

(Précision: l'opérateur unaire plus +xn'est pas l'opérateur pré-incrémenté ++x, ni l'opérateur post-incrémenté x++ni l'opérateur d'addition binaire x+y.)

Eric Lippert
la source
1
pour (int i = 0; i <plafond; i ++)
Michael Brown
13
Il ne parle pas de la préincrémentation et les opérateurs post - incrémentation: il parle du plus unaire, à l'opposé du signe négatif sur un numéro: +1 == 1. C'est sacrément proche d'un no-op.
Jesse C. Slicer
8
Il est non seulement de l'effet sur la machine sortie lisible, il peut améliorer l'apparence de code pour les humains: if(a == +1 || a == -1){...}.
Thomas Bratt
5
@ShuggyCoUK: Ce qui est particulièrement bizarre, c'est qu'il est surchargeable . Parce que ça arrive souvent. Vous savez, comment vous écrivez du JavaScript et vous pensez que mec, je souhaite que JS me permette de créer une sémantique unaire définie par l'utilisateur comme C # .
Eric Lippert
2
@Eric Je ne savais pas que c'était surchargeable. wow, vous pourriez faire de l'obscurcissement désagréable avec ça :)
ShuggyCoUk
12

Par défaut des littéraux numériques double

Pour la plupart des applications d' entreprise , decimalc'est plus approprié de toute façon ... ou peut-être qu'il serait préférable de simplement supprimer l'idée d'un défaut et de forcer le développeur à faire le choix.

(Ce « supprimer le défaut » serait approprié pour d'autres choses aussi. Par exemple, j'ai renoncé à essayer de convaincre tout le monde que les classes doivent être scellés par défaut, mais je pense qu'il est plus facile de persuader les gens qu'ils devraient penser au sujet si leur nouvelle classe doit être scellée ou non, et le rendre explicite.)

Jon Skeet
la source
Je préférerais peut-être identifier les littéraux qui impliquent une valeur qui ne peut pas être représentée précisément comme un double / flottant ...
ShuggyCoUk
S'ils sont en Java, référez-vous aux textes sacrés de Joshua Bloch "conception ou document pour héritage ou bien interdisez-le" martinfowler.com/bliki/DesignedInheritance.html Le kotlin de l'IIRC scelle les classes par défaut, donc une meilleure direction à cet égard.
Elazar Leibovich
Pourquoi les classes devraient-elles être scellées?
James
@James: Pour exactement les raisons que Josh donne. Concevoir une classe qui permet l'héritage de manière sensée et cohérente prend du temps - et le faire sans savoir comment l'héritage sera utilisé est encore pire.
Jon Skeet
1
@Pacerier: pensez à l'immuabilité, par exemple. Une classe non scellée ne peut pas prétendre être immuable, car les sous-classes peuvent introduire une mutabilité.
Jon Skeet
7

C'est plus une ligne directrice qu'une fonctionnalité, mais je pense que c'est important parce que c'est déjà trop ancré dans l'esprit des gens comme la meilleure solution canonique:

Le modèle officiel à mettre en œuvre IDisposable.

C'est lourd et il y a de meilleures façons .

Jordão
la source
6

Je sais qu'il y a de grandes différences entre les différentes classes de temporisation. Mais ne pourrions-nous pas nous débarrasser d'un ou deux d'entre eux, de toute façon?

nikie
la source
4

Méthodes et types de Arrayet List<T>qui sont devenus obsolètes avec Linq, par exemple:

  • Array.TrueForAll peut être remplacé par Enumerable.All
  • Array.FindAll peut être remplacé par Enumerable.Where
  • List<T>.ConvertAll peut être remplacé par Enumerable.Select
  • Predicate<T> peut être remplacé par Func<T, bool>
  • Converter<T,R> peut être remplacé par Func<T, R>
  • IComparer<T> devrait vraiment être un délégué Func<T, T, int>
nikie
la source
3
J'aime le Predicate<T>car il capture l'intention sur la façon dont la fonction est utilisée et économise un tout petit peu de frappe.
Zebi
2

Délégués non génériques Comme les collections non génériques, les délégués non génériques sont inutiles maintenant que nous avons les séries Func et Action. Et j'aurais coupé les variantes à trois paramètres. Si vous avez plus de trois paramètres, créez une structure et utilisez-la comme paramètre unique. Déclarer un délégué spécifique pour la gestion des événements n'est pas très SEC.

Michael Brown
la source
3
Comment définiriez-vous un délégué à une méthode qui prend un ref int avec Action ou Func? Comment définiriez-vous un combinateur avec Func? Autrement dit, il n'y a aucun moyen de dire "délégué DD (D d);" avec Func.
Eric Lippert
2
hmmm ... je me tiens corrigé. C'est pourquoi je laisse le travail de création des outils que j'utilise entre vos mains compétentes;)
Michael Brown
@EricLippert: J'aimerais voir une classe de délégués spéciale qui, via CLR magic, contiendrait des délégués de "chaque" zone et une combinaison de paramètres de valeur / référence [la recherche d'un délégué dans la classe magique avec un nom convenablement formaté créerait le type] et que tous les délégués de la signature appropriée en héritent. Le code qui veut un délégué particulier nécessiterait toujours un type exact, mais le code qui veut une signature particulière pourrait utiliser le nom magique.
supercat
-1

Services Web asmx

Je pense qu'ils sont assez obsolètes avec WCF de nos jours.

fretje
la source
6
Oui, mais parfois beaucoup plus facile à grogner. . .
Wyatt Barnett
-2

Winforms
Ce serait bien de ne pas avoir à naviguer entre deux plates-formes de bureau. WPF est où les choses vont, donc c'est frustrant d'avoir une redondance complète au niveau de la plate-forme.

Morgan Herlocker
la source
Winforms semble beaucoup plus stable, plus rapide et moins bogué que WPF ...
Pacerier
Lorsque vous avez juste besoin de pirater une petite application de bureau, WPF est une exagération majeure.
Kyralessa
Il semble qu'entre WPF est devenu assez obsolète en faveur de WinRT. Cependant, il me semble que Winforms est plus vivant que WPF dans le développement commercial. Voir aussi stackoverflow.com/questions/913417/…
Doc Brown