Uso de la palabra clave var en C #

406

Después de una discusión con colegas sobre el uso de la palabra clave 'var' en C # 3, me pregunté qué opiniones tenían las personas sobre los usos apropiados de la inferencia de tipos a través de var.

Por ejemplo, usé vagamente var en circunstancias cuestionables, por ejemplo: -

foreach(var item in someList) { // ... } // Type of 'item' not clear.
var something = someObject.SomeProperty; // Type of 'something' not clear.
var something = someMethod(); // Type of 'something' not clear.

Los usos más legítimos de var son los siguientes:

var l = new List<string>(); // Obvious what l will be.
var s = new SomeClass(); // Obvious what s will be.

Curiosamente, LINQ parece ser un área gris, por ejemplo: -

var results = from r in dataContext.SomeTable
              select r; // Not *entirely clear* what results will be here.

Está claro qué resultados habrá en que será un tipo que implemente IEnumerable, sin embargo, no es del todo obvio de la misma manera que una var que declara un nuevo objeto.

Es aún peor cuando se trata de LINQ a objetos, por ejemplo: -

var results = from item in someList
              where item != 3
              select item;

Esto no es mejor que el equitativo foreach (elemento var en someList) {// ...} equivilent.

Aquí existe una preocupación real sobre la seguridad de los tipos, por ejemplo, si colocamos los resultados de esa consulta en un método sobrecargado que acepta IEnumerable <int> e IEnumerable <double>, la persona que llama podría pasar el tipo incorrecto sin darse cuenta.

var no mantener la tipificación estricta, pero la pregunta es si realmente es peligroso para el tipo a no ser evidente de inmediato en la definición, algo que se magnifica cuando sobrecargas errores medios compilador no pueden ser emitidos cuando se pasa involuntariamente el tipo incorrecto de un método.

ljs
fuente
68
Usar var está bien, pero "No tengo que averiguar el tipo" parece una muy mala razón para usarlo ... se supone que debes saber cuál es el tipo, var es solo un atajo para evitar escribirlo
Thomas Levesque
53
var i = 0;== falla! var c = new CrazyFrigginLongClassName();== ganar!
dotjoe
66
"Var también me recuerda el tipo de variante VB / VBA. También tenía su lugar. Recuerdo (desde hace muchos años) que su uso era un tipo menos que deseable y que estaba hambriento de recursos". <- muestra que esta es una pregunta de cebo ya que el tipo 'var' de C # no tiene nada que ver con el tipo de variante VB / VBA.
user7116
20
var readabilityBeDamned = true;
spoulson
99
El problema con todos los ejemplos establecidos aquí es que estamos viendo UNA línea de código. Cuando veo línea tras línea de declaraciones "var", una tras otra, se sale de control. La legibilidad es subjetiva, pero encuentro que se abusa de Var mucho más de lo que se respeta.
jro

Respuestas:

293

Todavía creo que varpuede hacer que el código sea más legible en algunos casos. Si tengo una clase de Cliente con una propiedad de Órdenes, y quiero asignarla a una variable, simplemente haré esto:

var orders = cust.Orders;

No me importa si Customer.Orders es IEnumerable<Order>, ObservableCollection<Order>o BindingList<Order>- todo lo que quiero es mantener esa lista en la memoria para iterar sobre ella u obtener su recuento o algo más adelante.

Contraste la declaración anterior con:

ObservableCollection<Order> orders = cust.Orders;

Para mí, el nombre del tipo es solo ruido. Y si vuelvo y decido cambiar el tipo de Cliente. Ordena por el camino (digamos de ObservableCollection<Order>a IList<Order>) entonces también necesito cambiar esa declaración, algo que no tendría que hacer si hubiera usado var en el primer sitio.

Matt Hamilton
fuente
48
Me gusta tener el tipo explícito frente a mí cuando estoy leyendo el código. ¿Cómo sé qué "cust.Orders" está aquí sin el tipo? Sí, podría pasar el mouse para averiguarlo, pero ¿por qué debería hacerlo? :)
Jon Tackabury
77
Pero el punto es que en general no importa. Proporcionado cust.Orders es algo que puede enumerar (por ejemplo, foreach over), entonces no importa de qué tipo sea. El código adicional solo se interpone en la forma de leer la intención.
Matt Hamilton
67
Pero si solo necesita ese cust.Orders es "algo que puede enumerar", ¿entonces no lo declara como IEnumerable <Order> hace que ese requisito sea explícito y claro? Declararlo como var significa que efectivamente pierde ese requisito.
GrahamS
55
@jon y cómo IEnumerbal orders = cust.Orders foreach (var order in orders) marcan la diferencia? Lo único que dice IEnumerable es que puedes ponerlo en un foreach, pero ya lo sabías por la siguiente línea
Rune FS
18
"Lo único que dice IEnumerable es que puedes ponerlo en un foreach", también expresa la intención de que lo único que puedes hacer es enumerar. El uso de var da acceso e intellisense a los miembros públicos del tipo de colección concreta.
Joe
167

Yo uso varampliamente. Ha habido críticas de que esto disminuye la legibilidad del código, pero no hay argumento para apoyar esa afirmación.

Es cierto que puede significar que no está claro con qué tipo estamos tratando. ¿Y qué? Este es en realidad el objetivo de un diseño desacoplado. Cuando se trata de interfaces, no le interesa enfáticamente el tipo que tiene una variable. varaprovecha esta mucho más lejos, es cierto, pero creo que el argumento sigue siendo el mismo desde el punto de vista de la legibilidad: El programador no debe realmente estar interesado en el tipo de la variable, sino más bien en lo que una variable lo hace . Esta es la razón por la cual Microsoft también llama a la inferencia de tipos "duck typing".

Entonces, ¿qué hace una variable cuando la declaro usando var? Fácil, hace lo que IntelliSense me dice que haga. Cualquier razonamiento acerca de C # que ignore el IDE no llega a la realidad. En la práctica, cada código C # se programa en un IDE que admite IntelliSense.

Si estoy usando una varvariable declarada y me confundo para qué sirve la variable, hay algo fundamentalmente incorrecto en mi código. varno es la causa, solo hace visibles los síntomas. No culpes al mensajero.

Ahora, el equipo de # C ha publicado una guía de codificación que indica que vardebería solamente ser utilizado para capturar el resultado de una declaración de LINQ que crea un tipo anónimo (porque aquí, no tenemos ninguna alternativa real a var). Bueno, joder eso. Mientras el equipo de C # no me dé un argumento sólido para esta guía, voy a ignorarla porque, en mi opinión profesional y personal, es pura tontería. (Lo siento; no tengo ningún enlace a la directriz en cuestión).

En realidad, hay algunas (superficialmente) buenas explicaciones sobre por qué no deberías usarlas, varpero sigo creyendo que están equivocadas. Tomemos el ejemplo de "capacidad de búsqueda": el autor afirma que vardificulta la búsqueda de lugares donde MyTypese utiliza. Derecha. También las interfaces. En realidad, ¿por qué querría saber dónde se usa la clase? Podría estar más interesado en dónde se instancia y esto aún se podrá buscar porque en algún lugar se debe invocar a su constructor (incluso si esto se hace indirectamente, el nombre del tipo debe mencionarse en algún lugar).

Konrad Rudolph
fuente
14
En cualquier IDE decente, no utiliza una búsqueda de texto para obtener el uso de la clase, obtiene el IDE para hacerlo en función de su árbol de análisis o, de lo contrario, identifica los tipos de objetos. Como estamos hablando de tipeo estático, esto encontrará todo menos los tipos anónimos.
Dustman
66
Odiaría heredar 100k líneas de fuente sin documentación y uso liberal de var. Especialmente si combina var con nombres de variables poco útiles. Podría ver que es útil cuando ilustra un punto (o trata con tipos anónimos) pero en el código de producción.
Shea
77
Arnshea: bueno, ya has señalado el problema real allí: los nombres de variables inútiles y la documentación que falta . Realmente no veo qué varcontribuye a la confusión. Ciertamente, puede haber casos en los que es importante enfatizar el tipo / tamaño de una variable (por ejemplo, operaciones de bits de bajo nivel). Eso está bien: nadie afirmó que vardebería usarse exclusivamente. La regla es simple: si realmente causa confusión, no la use.
Konrad Rudolph
17
Cada ejemplo opuesto a var que he visto supone que el programador usará nombres de variables sin sentido. Pero tal vez es por eso que var es mejor que especificar explícitamente un tipo: obliga al programador a encontrar buenos nombres de variables.
Ryan Lundy
16
Microsoft también llama inferencia de tipos "tipear patos". - ¿De verdad? Me sorprendería ...
Anton Tykhyy
118

Var, en mi opinión, en C # es algo bueno tm . Cualquier variable que se escriba de este modo todavía se escribe con fuerza, pero obtiene su tipo del lado derecho de la asignación donde se define. Debido a que la información de tipo está disponible en el lado derecho, en la mayoría de los casos, es innecesario y excesivamente detallado también tener que ingresarla en el lado izquierdo. Creo que esto aumenta significativamente la legibilidad sin disminuir la seguridad del tipo.

Desde mi perspectiva, usar buenas convenciones de nomenclatura para variables y métodos es más importante desde una perspectiva de legibilidad que la información de tipo explícito. Si necesito la información de tipo, siempre puedo pasar el mouse sobre la variable (en VS) y obtenerla. Sin embargo, en general, la información de tipo explícito no debería ser necesaria para el lector. Para el desarrollador, en VS todavía obtienes Intellisense, independientemente de cómo se declare la variable. Habiendo dicho todo eso, todavía puede haber casos en los que tenga sentido declarar explícitamente el tipo; tal vez tenga un método que devuelva un List<T>, pero desee tratarlo como unIEnumerable<T>en tu método Para asegurarse de que está utilizando la interfaz, declarar la variable del tipo de interfaz puede hacerlo explícito. O, tal vez, desee declarar una variable sin un valor inicial, porque inmediatamente obtiene un valor basado en alguna condición. En ese caso necesitas el tipo. Si la información de tipo es útil o necesaria, continúe y úsela. Sin embargo, creo que normalmente no es necesario y el código es más fácil de leer sin él en la mayoría de los casos.

tvanfosson
fuente
3
Estoy de acuerdo en general. El punto clave aquí en mi opinión es estar seguro de que la intención es clara. Si no está claro para la mayoría de los desarrolladores del equipo, es perjudicial, no útil. Dicho esto, personalmente soy un ENORME fanático de esto, pero he tenido que contenerme un poco cuando otros desarrolladores de mi equipo han tenido problemas para determinar mi intención. Imagínate.
Steve Brouillard
3
Eh, me resulta más fácil de leer cuando el tipo está a la izquierda. Con ReSharper, no tengo que volver a escribir el tipo de la derecha de todos modos, por lo que no me molesta.
BlueRaja - Danny Pflughoeft
1
@BlueRaja: encuentro que usar buenos nombres de variables generalmente elimina la necesidad de molestarse con el tipo real de todos modos para comprender. Intellisense todavía está disponible en variables definidas "var", por lo que no necesito saber el tipo para elegir un método / propiedad al codificar.
tvanfosson
2
No se trata tanto de cuándo está codificando como de cuándo tiene que leer el código.
BlueRaja - Danny Pflughoeft
1
Debo estar en el lado grueso, entonces necesito un buen método y nombres de variables y una comprensión de los tipos que se operan para poder comprender correctamente el código que estoy leyendo. Creo que tienes razón, aunque es sintomático de problemas mayores. Uno de confianza. Para asegurarse de que el código está haciendo lo que parece estar haciendo, debe estar seguro de los tipos que se utilizan.
AnthonyWJones
91

Ninguno de esos es absolutamente cierto; varpuede tener efectos positivos y negativos sobre la legibilidad. En mi opinión, vardebería usarse cuando cualquiera de los siguientes es cierto:

  1. El tipo es anónimo (bueno, no tiene otra opción aquí, ya que debe ser var en este caso)
  2. El tipo es obvio en función de la expresión asignada (es decir var foo = new TypeWithAReallyLongNameTheresNoSenseRepeating())

varno tiene impactos en el rendimiento, ya que es azúcar sintáctico; el compilador infiere el tipo y lo define una vez que se compila en IL; no hay nada realmente dinámico al respecto.

Adam Robinson
fuente
1
estoy de acuerdo en ambos, aunque tengo restricciones largas sobre el segundo caso, si un tipo es tan largo, generalmente es un tipo genérico con muchos argumentos genéricos anidados, en ese caso un "Tipo corto equivalente a TypeWithAReallyLongNameTheresNoSenseRepeating" fuertemente tipado tiene más sentido
Ion Todirel
12
No deseo comenzar una guerra religiosa, pero personalmente tiendo a estar en desacuerdo con Ion. Preferiría un nombre de tipo muy largo pero muy preciso (tío Bob Martin) que un nombre de tipo abreviado y posiblemente ambiguo más corto. Agregaré la advertencia de que tampoco estoy de acuerdo con inflar artificialmente la longitud del nombre. Si 5 caracteres crean un nombre conciso que muestra claramente la intención, use 5 y no 25.
Steve Brouillard
2
@ Steve: Tengo que estar de acuerdo contigo; crear un "tipo corto" (que supongo que quiere decir que hereda del tipo genérico específico con el único fin de acortar el nombre) no es una buena práctica; requerirá que duplique y pase a través de cualquier constructor del tipo genérico, además de evitar que pase un tipo diferente que herede del tipo genérico a la función. Estás usando la herencia como typedefcuando no lo está.
Adam Robinson
77
¿Usar varcuando el tipo es obvio? Tal vez, pero la verdadera ganancia es cuando el tipo no importa. Si estás haciendo cosas así var customers = whatever; var query = from c in customers select stuff, no importa cuál sea el tipo exacto de 'clientes'. Es obvio cómo puedes usarlo, y eso es suficiente. Y si el tipo real es engorroso, vale la pena suprimirlo.
Joren
2
@ Kristoffer: puedo entender querer eliminar el desorden de las etiquetas, pero envolverlas en una clase no es (IMO) una alternativa aceptable, ya que luego se corta la posibilidad de que cualquier otra clase secundaria (legítima) de ese tipo genérico sea Un parámetro válido. Preferiría usar una using ShortType = LongGenericType<A,B,C>directiva en la parte superior de un archivo, ya que eso da la misma legibilidad, no requiere que vuelva a crear los constructores y no elimina las clases secundarias de ser candidatos.
Adam Robinson
68

De Eric Lippert, ingeniero sénior de diseño de software en el equipo de C #:

¿Por qué se varintrodujo la palabra clave?

Hay dos razones, una que existe hoy, una que surgirá en 3.0.

La primera razón es que este código es increíblemente feo debido a toda la redundancia:

Dictionary<string, List<int>> mylists = new Dictionary<string, List<int>>();

Y ese es un ejemplo simple: he escrito peor. Cada vez que se ve obligado a escribir exactamente lo mismo dos veces, es una redundancia que podemos eliminar. Mucho mejor para escribir

var mylists = new Dictionary<string,List<int>>();

y deje que el compilador descubra en qué tipo se basa la asignación.

En segundo lugar, C # 3.0 introduce tipos anónimos. Dado que los tipos anónimos, por definición, no tienen nombres, que necesita para ser capaz de inferir el tipo de la variable de la expresión de inicialización si su tipo es anónima.

El énfasis es mío. Todo el artículo, C # 3.0 todavía está estáticamente escrito, ¡honesto! , y las series que siguen son bastante buenas.

Esto es para lo que varsirve. Otros usos probablemente no funcionarán tan bien. Cualquier comparación con JScript, VBScript o escritura dinámica es una litera total. Tenga en cuenta de nuevo que vares necesario para que otras características funcionen en .NET.

Dustman
fuente
Encuentro extraño el argumento de Lippert. Nadie escribe el nombre de la segunda clase, dejan que Intellisense lo escriba por ellos, pero luego se da vuelta y afirma que var es mejor porque el compilador / Intellisense lo resuelve. ¡No puedes tenerlo en ambos sentidos!
Dave
55
El equipo de C # no controla intellisense, ellos controlan el compilador. En cualquier caso, ese no es el problema principal. No creo que var hubiera hecho los 100 puntos solo al guardar la escritura.
Dustman
@Dustman: var no guarda la escritura en absoluto. ¡Te hace escribir más!
Piotr Perak
53

Creo que el uso de var debería combinarse con nombres de variables elegidos sabiamente.

No tengo problemas para usar var en una declaración foreach, siempre que no sea así:

foreach (var c in list) { ... }

Si fuera más así:

foreach (var customer in list) { ... }

... entonces alguien que lea el código sería mucho más probable que entienda qué es "lista". Si tiene control sobre el nombre de la variable de lista en sí, eso es aún mejor.

Lo mismo puede aplicarse a otras situaciones. Esto es bastante inútil:

var x = SaveFoo(foo);

... pero esto tiene sentido:

var saveSucceeded = SaveFoo(foo);

Cada uno a lo suyo, supongo. Me encontré haciendo esto, lo cual es una locura:

var f = (float)3;

Necesito algún tipo de programa var de 12 pasos. Mi nombre es Matt y yo (ab) uso var.

Matt Hamilton
fuente
66
Bueno, lo único malo con "var f = (float) 3;" es que debería ser "var f = 3f" o "var f = 3.0 (causa una sola precisión)".
MichaelGG
3
Je, sí 3f o 3.0 es el camino a seguir! ¡Nosotros, los maníacos var, tenemos que mantenernos unidos!
Matt Hamilton
27
El verdadero problema en ese primer ejemplo es "lista", no "c". "lista" de qué ? "lista" debería renombrarse a "clientes", o "clientsWhoOweMoney", o "clientes actuales", o algo mucho más descriptivo. Y una vez que tenga eso, la "c" puede permanecer tal cual, porque ya sabe lo que contendrá.
Ryan Lundy
44
¡Hola Matt! Mi nombre es Kenny y soy un varaddict.
kenny
var MattHamil = "Luke Skywalker"; // le
quitamos
40

Hemos adoptado el "Código para personas, no para máquinas", basado en el supuesto de que usted pasa varias veces más tiempo en modo de mantenimiento que en un nuevo desarrollo.

Para mí, eso excluye el argumento de que el compilador "sabe" de qué tipo es la variable; claro, no puede escribir código no válido la primera vez porque el compilador detiene la compilación de su código, pero cuando el próximo desarrollador está leyendo el código dentro de 6 meses, deben poder deducir lo que la variable está haciendo correcta o incorrectamente e identificar rápidamente la causa de los problemas.

Así,

var something = SomeMethod();

está prohibido por nuestros estándares de codificación, pero se recomienda lo siguiente en nuestro equipo porque aumenta la legibilidad:

var list = new List<KeyValuePair<string, double>>();
FillList( list );
foreach( var item in list ) {
   DoWork( item ); 
}
Dexter
fuente
44
He descubierto que ("Código para personas, no para máquinas") es una pauta excelente: seguirla puede resultar en un mejor código y ayuda a evitar la optimización prematura.
Thanatos
3
No obtengo var list = new KeyValuePair <string, double>? Para mí, una lista puede tener más que una cosa.
TTT
"Código para personas, no para máquinas" - amen.
user1068352
39

No está mal, es más una cosa estilística, que tiende a ser subjetiva. Puede agregar inconsistencias, cuando usa var y cuando no lo hace.

Otro caso de preocupación, en la siguiente llamada, no se puede saber simplemente mirando el código del tipo devuelto por CallMe:

var variable = CallMe();

Esa es mi queja principal contra la var.

Uso var cuando declaro delegados anónimos en métodos, de alguna manera var se ve más limpio que si lo usara Func. Considera este código:

var callback = new Func<IntPtr, bool>(delegate(IntPtr hWnd) {
   ...
});

EDITAR : se actualizó el último ejemplo de código basado en la entrada de Julian

Ion Todirel
fuente
3
¿Pero realmente necesita saber el tipo allí mismo en esa línea? Sabes que CallMe devuelve algo; ¿No es suficiente saber que variablese crea una variable local llamada ? A menos que amplíe su ejemplo, esta no es una queja muy sólida, OMI.
Randolpho
2
No se trata de no ser detallado, se trata de no dejar que el compilador haga el azúcar de la sintaxis por usted. Considere esto: var getter ..., ahora este Func <object> getter ..., con el segundo sabe que no tiene que proporcionar ningún parámetro y lo que devuelve. Usted sabe desde el principio "qué hacer" y puede tomar decisiones más rápido, al diseñar algo o refactorizar. Tener toda la información a la mano es más importante que unos pocos caracteres más. Esto solo se puede apreciar cuando trabajas con mucho código.
Ion Todirel
2
Como todos estamos hablando de Visual Studio de todos modos, ¿cuál es el problema de pasar el mouse sobre la variable por un segundo y solo ver de qué tipo es? Mucho mejor que correr a la declaración de todos modos.
Rubys
3
Los nombres genéricos de variables y funciones ( variable, CallMe) son malos ejemplos. Sin embargo, si CallMe()fuera una función en algún tipo de "aplicación telefónica", var call = CallMe(); .... call.HangUp();tendría mucho más sentido.
Danko Durbić
3
@Randolpho: "¿cuál es la gran cosa acerca de pasar el mouse sobre la variable por un segundo y solo ver de qué tipo es?" Agrega tiempo a la sobrecarga de mantenimiento ... más un segundo es solo el tiempo de desplazamiento en lugar de contar el cambio de contexto del teclado al mouse. No sé sobre ti, pero trabajo con una fecha límite. Cada vez que tengo que pasar el mouse sobre una variable para averiguar de qué tipo es, es el momento en que podría haber pasado mejor solucionando un problema.
Powerlord
36

Var no es como una variante en absoluto. La variable todavía está fuertemente tipada, es solo que no presiona las teclas para obtenerla de esa manera. Puede pasar el mouse sobre él en Visual Studio para ver el tipo. Si está leyendo el código impreso, es posible que tenga que pensar un poco para averiguar cuál es el tipo. Pero solo hay una línea que lo declara y muchas líneas que lo usan, por lo que dar nombres decentes sigue siendo la mejor manera de hacer que su código sea más fácil de seguir.

¿Está usando Intellisense perezoso? Escribe menos que el nombre completo. ¿O hay cosas que son menos trabajo pero que no merecen críticas? Creo que los hay, y var es uno de ellos.

Kate Gregory
fuente
66
+1, la única persona en tener en cuenta que varno tiene nada que ver Variant.
user7116
27

El tiempo más probable que necesitará esto es para los tipos anónimos (donde es 100% requerido); pero también evita la repetición de los casos triviales, y la OMI aclara la línea. No necesito ver el tipo dos veces para una simple inicialización.

Por ejemplo:

Dictionary<string, List<SomeComplexType<int>>> data = new Dictionary<string, List<SomeComplexType<int>>>();

(por favor, no edite el hscroll en lo anterior, ¡¡¡esto prueba el punto !!!)

vs:

var data = new Dictionary<string, List<SomeComplexType<int>>>();

Sin embargo, hay ocasiones en que esto es engañoso y potencialmente puede causar errores. Tenga cuidado al usar varsi la variable original y el tipo inicializado no eran idénticos. Por ejemplo:

static void DoSomething(IFoo foo) {Console.WriteLine("working happily") }
static void DoSomething(Foo foo) {Console.WriteLine("formatting hard disk...");}

// this working code...
IFoo oldCode = new Foo();
DoSomething(oldCode);
// ...is **very** different to this code
var newCode = new Foo();
DoSomething(newCode);
Marc Gravell
fuente
1
(para obtener información, puede obtener problemas similares en todo lo que sea una conversión de tipo implícita)
Marc Gravell
1
No está de acuerdo con la parte que no desea ver dos veces en la misma línea. Es posible que en el futuro no esté creando directamente la variable después de declarar (por ejemplo, en un if debajo de la definición) que podría no estar claro directamente cuál es el tipo. La mayoría de los desarrolladores están acostumbrados a ver el tipo directamente al comienzo de la línea, especialmente en el código complejo que no desea dificultar la lectura del código.
Gertjan
@TheVillageIdiot - Revertí tu edición, porque en esta ocasión el hscroll está relacionado con el punto ;-p
Marc Gravell
2
@Gertjan: mi cerebro es limitado; si es complejo, no quiero verlo dos veces y tengo que comenzar a comparar (interfaz / concreto / etc.). Estoy feliz de verlo una vez y pensar "escrito como uno de ellos".
Marc Gravell
17

Un caso específico donde var es difícil: revisiones de código fuera de línea, especialmente las realizadas en papel.

No puede confiar en mouse-over para eso.

Jon Limjap
fuente
17
¿Por qué diablos estás revisando el código en papel? ¡Piensa en los árboles! ;)
Dustman
8
Puede tener el mismo problema sin usar var. El problema no es var; El problema son los malos nombres de variables. Si los nombres de las variables se eligen bien, el uso de var no importa.
Ryan Lundy
Tengo un chico en mi equipo que revisa su propio código y busca errores imprimiendo su código. Sus paredes están CUBIERTAS de código. Una vez entré y tenía una pizarra blanca completa cubierta con uno de sus ejercicios de depuración. Probablemente fue ~ 10000 LOC
Beep beep
Los nombres de variables por sí solos no resuelven el problema a menos que regrese a la notación húngara donde el tipo es parte del nombre.
Kevin Gale
17

No veo cuál es el gran problema ...

var something = someMethod(); // Type of 'something' not clear <-- not to the compiler!

Todavía tienes inteligencia completa sobre 'algo', y para cualquier caso ambiguo tienes tus pruebas unitarias, ¿verdad? ( ¿Vos si? )

No es varchar, no es tenue, y ciertamente no es un tipeo dinámico o débil. Está deteniendo a los locos como este:

List<somethinglongtypename> v = new List<somethinglongtypename>();

y reduciendo ese desorden mental total a:

var v = new List<somethinglongtypename>();

Agradable, no tan agradable como:

v = List<somethinglongtypename>();

Pero entonces para eso está Boo .

Frep D-Oronge
fuente
el tipo de 'algo' es muy claro para el compilador, internamente, la "var" se establece en el tipo de retorno de 'someMethod', es claro para el compilador, pero puede no ser claro para los desarrolladores que trabajan en el proyecto. y Boo está creciendo en mí rápidamente.
stephenbayer
No, v = List<somethinglongtypename>();ni siquiera es más agradable. Es importante distinguir entre la introducción de una nueva variable y la asignación a una variable existente.
HighCommander4
Bueno, si ha asignado a 'v' antes en el alcance actual, entonces es una asignación a una existente. De lo contrario, es la asignación a la nueva variable 'v'. Fácil.
Frep D-Oronge
17

Si alguien está usando la varpalabra clave porque no quiere "descifrar el tipo", esa es definitivamente la razón incorrecta. La varpalabra clave no crea una variable con un tipo dinámico, el compilador aún tiene que conocer el tipo. Como la variable siempre tiene un tipo específico, el tipo también debería ser evidente en el código si es posible.

Las buenas razones para usar la varpalabra clave son, por ejemplo:

  • Donde sea necesario, es decir, declarar una referencia para un tipo anónimo.
  • Donde hace que el código sea más legible, es decir, elimina las declaraciones repetitivas.

Escribir el tipo de datos a menudo hace que el código sea más fácil de seguir. Muestra qué tipos de datos está utilizando, de modo que no tiene que averiguar el tipo de datos descubriendo primero qué hace el código.

Guffa
fuente
11

Dado lo poderoso que es Intellisense ahora, no estoy seguro de que var sea más difícil de leer que tener variables miembro en una clase o variables locales en un método que se define fuera del área de la pantalla visible.

Si tiene una línea de código como

IDictionary<BigClassName, SomeOtherBigClassName> nameDictionary = new Dictionary<BigClassName, SomeOtherBigClassName>();

Es mucho más fácil o más difícil de leer que:

var nameDictionary = new Dictionary<BigClassName, SomeOtherBigClassName>();
Colin Desmond
fuente
Realmente no consideré esto, por lo que parece de la otra pregunta que es un punto bastante fuerte para usarlo en otro momento.
Finglas
Esa fue básicamente la única razón por la que lo implementaron (además de poder declarar tipos anónimos, pero podrían haber hecho de "var" una palabra clave especial que era solo para tipos anónimos)
Mqp
10

Creo que la clave con VAR es usarlo solo cuando sea apropiado, es decir, al hacer cosas en Linq que facilite (y probablemente en otros casos).

Si tiene un tipo para algo en el, entonces debe usarlo; no hacerlo es simple pereza (a diferencia de la pereza creativa que generalmente se fomenta), los buenos programadores a menudo trabajan muy duro para ser flojos y podrían considerarse la fuente de la cosa en primer lugar).

Una prohibición general es tan mala como abusar de la construcción en primer lugar, pero es necesario que exista un estándar de codificación razonable.

La otra cosa para recordar es que no es una variable de tipo VB en el sentido de que no puede cambiar los tipos, es una variable fuertemente tipada, es solo que se infiere el tipo (es por eso que hay personas que argumentan que no es irrazonable lo uso en, por ejemplo, un foreach, pero no estoy de acuerdo por razones de legibilidad y mantenibilidad).

Sospecho que este va a correr y correr (-:

Murph

Murph
fuente
10

Claro, intes fácil, pero cuando el tipo de la variable es IEnumerable<MyStupidLongNamedGenericClass<int, string>>, var hace las cosas mucho más fáciles.

Blorgbeard está fuera
fuente
2
+1 por esto. intversus vares algo para discutir, pero varios tipos genéricos anidados hacen varun regalo del cielo. Aquí es donde usar el nombre del tipo una y otra vez realmente destruye la legibilidad del código.
Chris Farmer
Esta es absolutamente la razón equivocada para usarlo. Si su código usa un tipo genérico anidado, debe derivar una clase con nombre específica para él. Por ejemplo: class IntStringEnumerator : IEnumerable<MyStupidLongNamedGenericClass<int, string>>y luego use el nuevo nombre. Eso limpia el código y describe mejor el tipo.
xxbbcc
Muy bien, pero mi ejemplo fue simplemente una hipérbole. IntStringEnumerator i = new IntStringEnumerator()Todavía está escribiendo demasiado.
Blorgbeard sale
9

Robado de la publicación sobre este tema en CodingHorror :


Desafortunadamente, usted y todos los demás se equivocaron. Si bien estoy de acuerdo con usted en que la redundancia no es algo bueno, la mejor manera de resolver este problema habría sido hacer algo como lo siguiente:

MyObject m = nuevo ();

O si está pasando parámetros:

Persona p = nuevo ("Nombre", "Apellido);

Donde en la creación de un nuevo objeto, el compilador infiere el tipo desde el lado izquierdo, y no el derecho. Esto tiene otras ventajas sobre "var", ya que podría usarse también en declaraciones de campo (también hay algunas otras áreas en las que podría ser útil también, pero no voy a entrar aquí).

Al final, no estaba destinado a reducir la redundancia. No me malinterpreten, "var" es MUY importante en C # para tipos / proyecciones anónimas, pero el uso aquí está MUY BIEN (y he estado diciendo esto durante mucho, mucho tiempo) ya que ofuscas el tipo que esta siendo usado. Tener que escribirlo dos veces es muy frecuente, pero declararlo cero veces es muy poco.

Nicholas Paldino .NET / C # MVP el 20 de junio de 2008 08:00 a.m.


Supongo que si tu principal preocupación es tener que escribir menos, entonces no hay ningún argumento que te impida usarlo.

Si sólo se va a alguna vez ser la persona que mira a su código, a continuación, a quién le importa? De lo contrario, en un caso como este:

var people = Managers.People

está bien, pero en un caso como este:

var fc = Factory.Run();

Cortocircuita cualquier tipo de deducciones inmediatas que mi cerebro pueda comenzar a formar a partir del "inglés" del código.

De lo contrario, solo use su mejor criterio y programa 'cortesía' hacia otras personas que podrían tener que trabajar en su proyecto.

Rostov
fuente
44
Sus ejemplos anteriores no son un argumento para no usar var; son un argumento para usar buenos nombres de variables descriptivas. Si, en lugar de [var fc = Factory.Run ();] tuvieras [bool fc = Factory.Run ();], el código no quedaría más claro.
Ryan Lundy
9

Usar en varlugar del tipo explícito hace que las refactorizaciones sean mucho más fáciles (por lo tanto, debo contradecir los carteles anteriores que significaban que no había diferencia o que era puramente "azúcar sintáctico").

Puede cambiar el tipo de retorno de sus métodos sin cambiar todos los archivos donde se llama a este método. Imagina

...
List<MyClass> SomeMethod() { ... }
...

que se usa como

...
IList<MyClass> list = obj.SomeMethod();
foreach (MyClass c in list)
  System.Console.WriteLine(c.ToString());
...

Si desea refactorizar SomeMethod()para devolver un IEnumerable<MySecondClass>, tendría que cambiar la declaración de variable (también dentro de foreach) en cada lugar donde utilizó el método.

Si tú escribes

...
var list = obj.SomeMethod();
foreach (var element in list)
  System.Console.WriteLine(element.ToString());
...

en cambio, no tienes que cambiarlo.

MartinStettner
fuente
de acuerdo, preguntándome por qué este agradable efecto secundario no se promociona tanto como algunos de los otros profesionales más subjetivos en las respuestas más populares.
fieldingmellish
Me ha pasado hoy. Tengo una clase de fábrica que devuelve la isancia de una clase MainMenu. Hoy creé un MainMenu2 con la misma interfaz de MainMenu. ¡Tengo mi código de aplicación intacto después del cambio!
Marco Staffoli
8

@aku: Un ejemplo son las revisiones de código. Otro ejemplo es la refactorización de escenarios.

Básicamente no quiero ir a escribir con mi mouse. Puede que no esté disponible.

erlando
fuente
2
Es interesante que digas eso porque var puede simplificar la refactorización. Si ha usado var, no tiene que hacerlo. Ahora siempre puede confiar en las herramientas de refactorización del IDE, pero ya sabe, siempre puede confiar en el IDE para el tipo también :)
Fred
8

Es cuestión de gustos. Todo este alboroto sobre el tipo de variable desaparece cuando te acostumbras a los idiomas escritos dinámicamente. Es decir, si alguna vez comienza a gustarles (no estoy seguro de si todos pueden, pero a mí sí).

C # 's vares bastante bueno ya que parece una escritura dinámica, pero en realidad es una escritura estática : el compilador impone el uso correcto.

El tipo de su variable no es realmente tan importante (esto se ha dicho antes). Debe ser relativamente claro por el contexto (sus interacciones con otras variables y métodos) y su nombre: no espere que customerList contenga un int...

Todavía estoy esperando ver qué piensa mi jefe sobre este asunto: obtuve una "manta" para usar cualquier construcción nueva en 3.5, pero ¿qué haremos con respecto al mantenimiento?

Daren Thomas
fuente
7

En su comparación entre IEnumerable<int>y IEnumerable<double>no necesita preocuparse: si pasa el tipo incorrecto, su código no se compilará de todos modos.

No hay preocupación por la seguridad de tipos, ya varque no es dinámica. Es solo magia de compilación y cualquier tipo de llamadas inseguras que hagas quedarán atrapadas.

Var es absolutamente necesario para Linq:

var anonEnumeration =
    from post in AllPosts()
    where post.Date > oldDate
    let author = GetAuthor( post.AuthorId )
    select new { 
        PostName = post.Name, 
        post.Date, 
        AuthorName = author.Name
    };

Ahora mira anonEnumeration en intellisense y aparecerá algo así comoIEnumerable<'a>

foreach( var item in anonEnumeration ) 
{
    //VS knows the type
    item.PostName; //you'll get intellisense here

    //you still have type safety
    item.ItemId;   //will throw a compiler exception
}

El compilador de C # es bastante inteligente: los tipos anon generados por separado tendrán el mismo tipo generado si sus propiedades coinciden.

Fuera de eso, siempre que tenga inteligencia, tiene sentido usar en varcualquier lugar donde el contexto sea claro.

//less typing, this is good
var myList = new List<UnreasonablyLongClassName>();

//also good - I can't be mistaken on type
var anotherList = GetAllOfSomeItem();

//but not here - probably best to leave single value types declared
var decimalNum = 123.456m;
Keith
fuente
Deshágase IQueriable<T>antes de repetir: anonEnumeration.ToList();
David Diez
@DavidDiez, ¿podrías reformular? Tu afirmación no tiene sentido. Ninguno de mis fragmentos de código hace referencia IQueryableo.ToList()
Keith
var anonEnumeration = from post in AllPosts() where post.Date > oldDate let author = GetAuthor( post.AuthorId ) select new { PostName = post.Name, post.Date, AuthorName = author.Name };no devuelve un IQueriable<T>?
David Diez
1
@DavidDiez depende de lo que AllPosts()regrese: el autor de la pregunta se refiere, List<T>así que supuse eso. En ese caso, el resultado es que anonEnumerationserá de tipo IEnumerable<'a>. Ahora, si se AllPosts()devuelve IQueryable<T>, anonEnumerationse convertirá IQueryable<'a>(nota no ien Queryable); sin embargo, en ese caso, mi código aún funciona porque se IQueryable<T>implementa IEnumerable<T>. Aquí hay un montón de mejores preguntas y respuestas sobre las distinciones entre ellos; aquí mi caso es que 'aes anónimo y le varpermite asignarlo a una variable estáticamente tipada.
Keith
Ohh ya veo, gracias por explicarlo :) Mi comentario fue porque iterar un IQueryable<T>no es una buena práctica porque en cada iteración estás haciendo una declaración de lectura en DB. Asegúrese de hacerlo *.ToList() IQueryable<T>antes de repetirlos
David Diez
7

Supongo que depende de tu perspectiva. Personalmente, nunca he tenido ninguna dificultad para entender un código debido al var"mal uso", y mis compañeros de trabajo y yo lo usamos bastante. (Estoy de acuerdo en que Intellisense es una gran ayuda en este sentido). Lo acojo con satisfacción como una forma de eliminar la ruina repetitiva.

Después de todo, si declaraciones como

var index = 5; // this is supposed to be bad

var firstEligibleObject = FetchSomething(); // oh no what type is it
                                            // i am going to die if i don't know

si fuera realmente imposible de tratar, nadie usaría lenguajes escritos dinámicamente.

mqp
fuente
Presumiblemente en .Net 4 donde los tipos dinámicos son lugares comunes, ¿esto será más importante?
Colin Desmond
2
Por el contrario, si está confundido por "var" ahora, esperaría que usted también esté confundido por "dinámico". Dios no lo quiera nadie declara una dinámica y luego hace una referencia a él mediante "var" :)
MQP
Quise decir algo como d = 52 dinámico; var x = d; que debería estar bien
mqp
7

Solo uso var cuando está claro para ver qué tipo se usa.

Por ejemplo, usaría var en este caso, porque puede ver de inmediato que x será del tipo "MyClass":

var x = new MyClass();

NO usaría var en casos como este, porque tiene que arrastrar el mouse sobre el código y mirar la información sobre herramientas para ver qué tipo de MyFunction devuelve:

var x = MyClass.MyFunction();

Especialmente, nunca uso var en los casos en que el lado derecho ni siquiera es un método, sino solo un valor:

var x = 5;

(porque el compilador no puede saber si quiero un byte, short, int o lo que sea)

Christian Specht
fuente
Si el lado derecho no es lo suficientemente claro como para justificar el uso de var, entonces varno es el problema: el lado derecho es el problema. No es lo suficientemente descriptivo . Customer c = GetContext()es todavía poco claro y no es mejor que usar var.
JulianR
6

Para mí, la antipatía hacia varilustra por qué el bilingüismo en .NET es importante. Para aquellos programadores de C # que también han hecho VB .NET, las ventajas de varson intuitivamente obvias. La declaración estándar de C # de:

List<string> whatever = new List<string>();

es el equivalente, en VB .NET, de escribir esto:

Dim whatever As List(Of String) = New List(Of String)

Sin embargo, nadie hace eso en VB .NET. Sería una tontería, porque desde la primera versión de .NET has podido hacer esto ...

Dim whatever As New List(Of String)

... que crea la variable y la inicializa todo en una línea razonablemente compacta. Ah, pero ¿y si quieres un IList<string>, no un List<string>? Bueno, en VB .NET eso significa que tienes que hacer esto:

Dim whatever As IList(Of String) = New List(Of String)

Al igual que tendría que hacer en C #, y obviamente no podría usar varpara:

IList<string> whatever = new List<string>();

Si necesita que el tipo sea algo diferente, puede serlo. Pero uno de los principios básicos de una buena programación es reducir la redundancia, y eso es exactamente lo que hace var.

Ryan Lundy
fuente
1
Es curioso que mencione el bilingüismo como algo que promueve el uso de var. ¡Mi antagonismo hacia la palabra clave var proviene directamente de mi fluidez en javascript! :)
urig
varen C # no tiene conexión alguna con varJavaScript. Una varvariable declarada en C # está fuertemente tipada.
Ryan Lundy
6

Úselo para tipos anónimos, para eso está allí. Cualquier otra cosa es un uso demasiado lejos. Como muchas personas que crecieron en C, estoy acostumbrado a mirar a la izquierda de la declaración para el tipo. No miro al lado derecho a menos que tenga que hacerlo. Usar varpara cualquier declaración antigua me hace hacerlo todo el tiempo, lo que personalmente me resulta incómodo.

Aquellos que dicen 'no importa, usa lo que te hace feliz' no están viendo la imagen completa. Todos recogerán el código de otras personas en un momento u otro y tendrán que lidiar con las decisiones que tomaron en el momento en que lo escribieron. Ya es bastante malo tener que lidiar con convenciones de nomenclatura radicalmente diferentes, o, la queja clásica, estilos de refuerzo, sin agregar todo ' varo no' a la mezcla. El peor de los casos será cuando un programador no usó vary luego viene un mantenedor que lo ama y extiende el código usándolo. Así que ahora tienes un lío impío.

Los estándares son algo bueno precisamente porque significan que es mucho más probable que pueda recoger código aleatorio y poder asimilarlo rápidamente. Cuantas más cosas sean diferentes, más difícil será. Y pasar al estilo 'var en todas partes' hace una gran diferencia.

No me importa la escritura dinámica, y no me importa la escritura implícita, en idiomas diseñados para ellos. Me gusta bastante Python. Pero C # fue diseñado como un lenguaje estáticamente tipado explícitamente y así es como debe permanecer. Romper las reglas para los tipos anónimos fue bastante malo; dejar que la gente lo lleve aún más lejos y rompa aún más los modismos del idioma es algo con lo que no estoy contento. Ahora que el genio está fuera de la botella, nunca volverá a entrar. C # será balcanizado en campamentos. No está bien.

Neil Hewitt
fuente
77
Guau. Ignorar todos los argumentos presentados en este hilo hasta ahora y volver a establecer toda la discusión es todo un logro.
Konrad Rudolph el
Este 100% describe cómo me siento acerca de 'var', particularmente desde el punto de vista de elegir el código de otra persona. El uso de var cambia radicalmente la tarea en cuestión si está llena de basura. +1
Simon
6

Muchas veces durante las pruebas, me encuentro con un código como este:

var something = myObject.SomeProperty.SomeOtherThing.CallMethod();
Console.WriteLine(something);

Ahora, a veces, querré ver qué contiene SomeOtherThing, SomeOtherThing no es del mismo tipo que devuelve CallMethod (). Sin embargo, como estoy usando var, solo cambio esto:

var something = myObject.SomeProperty.SomeOtherThing.CallMethod();

a esto:

var something = myObject.SomeProperty.SomeOtherThing;

Sin var, también tendría que seguir cambiando el tipo declarado en el lado izquierdo. Sé que es menor, pero es extremadamente conveniente.

BFree
fuente
6

Para los aficionados que piensan que varahorran tiempo, se necesitan menos pulsaciones de teclas para escribir:

StringBuilder sb = new StringBuilder();

que

var sb = new StringBuilder();

Cuenta si no me crees ...

19 contra 21

Explicaré si es necesario, pero solo pruébalo ... (dependiendo del estado actual de tu inteligencia, es posible que tengas que escribir un par más para cada uno)

¡Y es cierto para cada tipo que se te ocurra!

Mi sensación personal es que nunca se debe usar var, excepto donde no se conoce el tipo porque reduce la legibilidad de reconocimiento en el código. El cerebro tarda más en reconocer el tipo que una línea completa. Los veteranos que entienden el código de máquina y los bits saben exactamente de lo que estoy hablando. El cerebro procesa en paralelo y cuando usas var lo obligas a serializar su entrada. ¿Por qué alguien querría hacer que su cerebro trabaje más? Para eso están las computadoras.

Wray Smallwood
fuente
Encuentro la repetición de stringBuilder sb = new StringBuilder () desordenada y más larga para reconocerla claramente. Es ruido extra. ¡El problema es que determinar qué constituye y qué no constituye un esfuerzo intelectual adicional para comprender algún código es bastante subjetivo!
ljs
"var nunca debe usarse, excepto donde no se conoce el tipo ..." - SIEMPRE puede conocer el tipo, al igual que el compilador. Esto no es una escritura dinámica, solo permite que el compilador determine el tipo por usted. Pero el tipo nunca es un desconocido.
Gabriel Magana
5

Divido var por todos los lugares, los únicos lugares cuestionables para mí son los tipos cortos internos, por ejemplo, prefiero int i = 3;sobrevar i = 3;

robi-y
fuente
5

Ciertamente puede simplificar las cosas, del código que escribí ayer:

var content  = new Queue<Pair<Regex, Func<string, bool>>>();
...
foreach (var entry in content) { ... }

Esto habría sido extremadamente detallado sin var.

Anexo: Un poco de tiempo dedicado a un lenguaje con inferencia de tipo real (por ejemplo, F #) mostrará cuán buenos son los compiladores para obtener el tipo correcto de expresiones. Ciertamente ha significado que tiendo a usar vartodo lo que puedo, y usar un tipo explícito ahora indica que la variable no es del tipo de expresión inicializadora.

Richard
fuente
Sí, los compiladores son más inteligentes que nosotros, ¡supéralo!
Benjol