¿C # o .Net características para cortar suponiendo que no se necesita compatibilidad con versiones anteriores? [cerrado]

18

Cualquier producto o marco evoluciona. Principalmente se hace para satisfacer las necesidades de sus usuarios, aprovechar las nuevas capacidades informáticas y simplemente mejorarlo. A veces, el objetivo principal del diseño también cambia con el producto. C # o .net framework no es una excepción. Como vemos, la cuarta versión actual es muy diferente en comparación con la primera. Pero la cosa viene como una barrera para esta evolución: compatibilidad con versiones anteriores.

En la mayoría de los frameworks / productos, hay características que se habrían cortado si no hubiera necesidad de soportar la compatibilidad con versiones anteriores. Según usted, ¿cuáles son estas características en C # /. Net?

Por favor mencione una característica por respuesta.

Gulshan
fuente
Palabra clave nueva
Nemanja Trifunovic
44
La pregunta claramente no es constructiva de acuerdo con las pautas, y claramente constructiva basada en las respuestas fantásticas. Votación para volver a abrir.
psr
1
lástima que haya cerrado, ¿aún así Eric puede bloguear esto en lugar de responder aquí?
jk.

Respuestas:

35

Métodos anónimos . Creo que todos están de acuerdo en que la sintaxis del método anónimo elegido para C # 2.0 es gruesa y torpe en comparación con la sintaxis lambda que agregamos a C # 3.0. Es profundamente desafortunado tener dos sintaxis casi idénticas para hacer lo mismo.

Eric Lippert
fuente
1
De acuerdo, los métodos anónimos eran geniales cuando no teníamos lambdas ... ahora son redundantes.
Michael Brown
99
Hay una característica especial de los métodos anónimos que es mucho mejor que las expresiones lambda ... ¡su nombre perfecto!
explorest
1
En este punto, ni siquiera recuerdo la sintaxis de un método anónimo en C #. Tendría que buscarlo si por alguna extraña razón necesito usar uno en lugar de una lambda.
Kyralessa
33

Me desharía de las colecciones no genéricas. Son una abominación ... y hay muchos casos en los que estoy usando linq y tengo que hacer algo como

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

Cada vez que tengo que hacer eso, una pequeña parte de mi alma muere.

Michael Brown
fuente
Esto es muy bueno
1
No todos los puertos de .NET admiten genéricos. .NET Micro es un ejemplo. Es posible que no se aplique si CustomObjects nunca se moverá a esta plataforma.
goodguys_activate
2
Esa es la ventaja de no tener alma.
CaffGeek
29

nulo como un tipo . ¿Por qué demonios es "vacío" un tipo? No tiene instancias, no tiene valores, no puede usarlo como argumento de tipo genérico, tipo de parámetro formal, tipo local, tipo de campo o tipo de propiedad. No tiene significado como tipo; más bien, es un hecho sobre el efecto que tiene una llamada al método en la pila de la máquina virtual. Pero la máquina virtual es solo eso: una máquina virtual. ¡La máquina real pondrá el valor devuelto en un registro (típicamente EAX en x86) y no afectará en absoluto a la pila! El vacío como tipo es solo una mala idea en general.

Peor: cuando se usa en un tipo de puntero, ya void*que significa algo completamente diferente de lo que significa cuando se usa como tipo de retorno. Ahora significa "un puntero a una ubicación de almacenamiento de tipo desconocido", que no tiene nada que ver con su significado como "un método que no devuelve ningún valor".

Podemos reemplazar void*como un tipo de puntero con IntPtr. (Y void**con IntPtr*y así sucesivamente.) Podemos reemplazar el vacío como un tipo de retorno con "Unidad", un tipo que tiene un solo valor, es decir, nulo. Una implementación del CLR podría decidir que una llamada de función de tipo unidad podría optimizar su uso de registros o pilas de manera apropiada, sabiendo que el valor nulo que se está "devolviendo" puede ignorarse de manera segura.

En un mundo así, ya no necesita separarse Func<A, R>y Action<T>delegados. Action<T>es justo Func<T, Unit>.

Eric Lippert
fuente
44
... y Taskes solo un Task<Unit>. Reimplementar los bits de la biblioteca del CTP asíncrono me hizo realmente desear esto ...
Jon Skeet
24

La declaración vacía; . Propenso a errores, casi siempre es un error tipográfico, y no le da ningún significado adicional que no esté expresado por {}.

Eric Lippert
fuente
77
Sin mencionar la gran penalización de rendimiento bajo el JIT de 64 bits </snark>.
Jesse C. Slicer
77
¿Una declaración vacía tiene una penalización de rendimiento? ¿Porqué es eso?
quentin-starin
22

Covarianza insegura en matrices de tipo de referencia . Con la covarianza typesafe activada IEnumerable<T>, al menos parte de la necesidad de covarianza de matriz ha desaparecido. (Si tuviéramos una interfaz de lista de solo lectura covariante, entonces no la necesitaríamos en absoluto).

Eric Lippert
fuente
Absolutamente iba a escribir esto cuando vi el título de la pregunta: me ganaste :(
Chris Smith
1
Es útil la capacidad de recibir una referencia de matriz covariante y escribir de forma segura en las referencias de matriz que se leyeron . Si se IList<T>hereda IReadableList<out T>y no es genérico IPemutable, podría admitir cosas como la ordenación, pero las matrices lo admiten más fácilmente.
supercat
14

El operador unario plus . El operador menos útil de todos los tiempos. Si no tuviéramos que guardarlo para compatibilidad con versiones anteriores, lo sacaría en un santiamén. ¿Quién usa esta cosa, alguien?

(Aclaración: el operador unario más +xno es el operador de preincremento ++x, ni el operador de postincremento ni el operador de x++suma binaria x+y).

Eric Lippert
fuente
1
para (int i = 0; i <techo; i ++)
Michael Brown
13
Él no está hablando de la preincremento y operadores postincremento: él está hablando de la más unario, lo contrario del signo negativo en un número: +1 == 1. Es bastante cerca de un no-op.
Jesse C. Slicer
8
No es sólo por el efecto sobre la salida legible por máquina, se puede mejorar el aspecto de código para los seres humanos: if(a == +1 || a == -1){...}.
Thomas Bratt
55
@ShuggyCoUK: Lo que es particularmente extraño al respecto es que se puede cargar . Porque eso pasa mucho. Ya sabes, cómo estás escribiendo JavaScript y piensas hombre, desearía que JS me permitiera hacer una semántica de operador unario más definida por el usuario como lo hace C # .
Eric Lippert el
2
@Eric No me di cuenta de que era sobrecargable. wow podrías ofuscar algo desagradable con eso :)
ShuggyCoUk
12

Los literales numéricos predeterminados a double

Para la mayoría de los negocios aplicaciones , decimales más apropiado de todos modos ... o tal vez sería mejor simplemente eliminar la idea de un valor predeterminado y obligar al desarrollador a tomar la decisión.

(Eso "eliminar el defecto" sería apropiado para algunas otras cosas, también. Por ejemplo, he renunciado a tratar de convencer a todo el mundo que las clases deben ser sellados por defecto, pero sospecho que es más fácil convencer a la gente que debe pensar acerca si su nueva clase debe sellarse o no, y hacerlo explícito).

Jon Skeet
fuente
Tal vez me inclinaría a identificar literales que impliquen un valor que no pueda representarse como un doble / flotante con precisión ...
ShuggyCoUk
Si están interesados ​​en Java, remítalos a los textos sagrados de Joshua Bloch "diseño o documento de herencia o prohíbalo " martinfowler.com/bliki/DesignedInheritance.html IIRC kotlin sella las clases por defecto, por lo que la industria se está moviendo hacia Una mejor dirección a este respecto.
Elazar Leibovich
¿Por qué deberían sellarse las clases?
James
@ James: Por exactamente las razones que Josh da. Diseñar una clase que permita la herencia de una manera sensata y consistente lleva tiempo, y hacerlo sin saber cómo se va a usar la herencia es aún peor.
Jon Skeet
1
@Pacerier: Piense en la inmutabilidad, por ejemplo. Una clase no sellada no puede pretender ser inmutable, ya que las subclases pueden introducir mutabilidad.
Jon Skeet
7

Esta es más una guía que una característica, pero creo que es importante porque ya está demasiado arraigada en la mente de las personas como la mejor solución canónica:

El patrón oficial para implementarIDisposable .

Es engorroso y hay mejores formas .

Jordão
fuente
6

Yo que hay grandes diferencias entre las distintas clases de temporizador. ¿Pero no podríamos deshacernos de uno o dos de ellos?

nikie
fuente
4

Métodos y tipos de Arrayy List<T>que se volvieron obsoletos con Linq, por ejemplo:

  • Array.TrueForAll puede ser reemplazado con Enumerable.All
  • Array.FindAll puede ser reemplazado con Enumerable.Where
  • List<T>.ConvertAll puede ser reemplazado con Enumerable.Select
  • Predicate<T> puede ser reemplazado con Func<T, bool>
  • Converter<T,R> puede ser reemplazado con Func<T, R>
  • IComparer<T> realmente debería ser un delegado Func<T, T, int>
nikie
fuente
3
Me gusta Predicate<T>porque captura la intención de cómo se usa la función y ahorra un poco de tipeo.
Zebi
2

Delegados no genéricos Al igual que las colecciones no genéricas, los delegados no genéricos son inútiles ahora que tenemos las series Func y Action. Y habría cortado las variantes en tres parámetros. Si tiene más de tres parámetros, cree una estructura y úsela como parámetro único. Declarar un delegado específico para el manejo de eventos no es muy SECO.

Michael Brown
fuente
3
¿Cómo definiría un delegado a un método que toma una referencia int con Action o Func? ¿Cómo definirías un combinador con Func? Es decir, no hay forma de decir "delegar DD (D d)"; con Func.
Eric Lippert
2
hmmm ... estoy corregido. Es por eso que dejo el trabajo de crear las herramientas que uso en tus manos capaces;)
Michael Brown
@EricLippert: Me gustaría ver una clase especial de delegados que a través de la magia CLR contenga delegados de "cada" aridad y combinación de parámetros de valor / referencia [la búsqueda de un delegado en la clase mágica con un nombre con el formato adecuado crearía escriba], y haga que todos los delegados de la firma adecuada hereden de eso. El código que quiere un delegado particular aún requeriría un tipo exacto, pero el código que quiere una firma particular podría usar el nombre mágico.
supercat
-1

Servicios web asmx

Creo que son bastante obsoletos con WCF hoy en día.

fretje
fuente
66
Sí, pero a veces es mucho más fácil de asimilar. . .
Wyatt Barnett
-2

Winforms
Sería bueno no tener que navegar entre dos plataformas de escritorio. WPF es donde van las cosas, por lo que es frustrante tener una redundancia completa a nivel de plataforma.

Morgan Herlocker
fuente
Winforms parece mucho más estable, más rápido y con menos errores que WPF ...
Pacerier
Cuando solo necesita hackear una pequeña aplicación de escritorio, WPF es una gran exageración.
Kyralessa
Parece que entre WPF se ha vuelto bastante obsoleto a favor de WinRT. Sin embargo, para mí parece que Winforms está más vivo que WPF en el desarrollo empresarial. Ver también stackoverflow.com/questions/913417/…
Doc Brown