Qué usar: var o nombre del objeto?

esta es una pregunta que cuando programo siempre me pregunto: qué usar cuando estamos escribiendo código:

var myFiles = Directory.GetFiles(fullPath); 

o

 string[] myFiles = Directory.GetFiles(fullPath); 

var es nuevo y es una variable local implícitamente tipada , por lo que solo podemos usarla localmente y tiene reglas como no puede ser nula, etc., pero me pregunto si obtendremos alguna ventaja de usarla “normalmente”.

La parte “normalmente” dice, no en Tipos Anónimos , Inicializadores de Objetos y Colecciones y Expresiones de Consulta, donde esa era la intención de usar el objeto var anónimo, entonces lo que quiero decir es … al igual que en el ejemplo anterior.

¿Cuáles son tus pensamientos?

Más allá del uso obvio de var con LINQ, también lo utilizo para abreviar las declaraciones variables pilosas para la legibilidad, por ejemplo:

 var d = new Dictionary>>(); 

En general, obtengo una especie de consuelo (a falta de una mejor palabra) del tipado estático que me hace reacio a renunciar a él. Me gusta la sensación de que sé lo que estoy haciendo cuando declaro una variable. Declarar una variable no es solo decirle al comstackdor algo, sino decirle a la persona que lee algo sobre su código.

Dejame darte un ejemplo. Supongamos que tengo un método que devuelve una List . Este código es ciertamente correcto, y creo que es cómo el 90% de los desarrolladores de C # probablemente lo escribirían:

 List list = MyMethod(); 

Obviamente, ¿verdad? De hecho, aquí hay un lugar donde puedes usar var .

Suficientemente cierto. Pero esta versión del código no solo declara una variable, sino que me dice lo que la persona que lo escribió tiene la intención de hacer:

 IEnumerable list = MyMethod(); 

El desarrollador que escribió ese código me dice: “No voy a cambiar esta lista, ni voy a usar un índice para acceder a sus miembros. Todo lo que voy a hacer es repetirlo”. Esa es una gran cantidad de información para transmitir en una sola línea de código. Es algo a lo que te rindes si usas var .

Por supuesto, no lo vas a dejar si no lo estabas usando en primer lugar. Si eres el tipo de desarrollador que escribiría esa línea de código, ya sabes que no usarías var allí.

Editar:

Acabo de volver a leer la publicación de Jon Skeet, y esta cita de Eric Lippert saltó sobre mí:

Los lugareños implícitamente tipeados son solo una pequeña forma en la que puedes restar importancia al cómo y enfatizar el qué.

Creo que, en realidad, en muchos casos el uso de tipeo implícito es lo que está implícito. Está bien no pensar en el qué. Por ejemplo, casualmente escribiré una consulta LINQ como:

 var rows = from DataRow r in parentRow.GetChildRows(myRelation) where r.Field("Flag") orderby r.Field("SortKey") select r; 

Cuando leo ese código, una de las cosas que pienso cuando lo leo es ” rows es un IEnumerable “. Porque sé que lo que devuelven las consultas LINQ es IEnumerable , y puedo ver el tipo de objeto que se está seleccionando allí mismo.

Ese es un caso donde lo que no se ha hecho explícito. Me ha sido permitido inferir.

Ahora, en aproximadamente el 90% de los casos en los que uso LINQ, esto no importa un poquito. Porque el 90% del tiempo, la siguiente línea de código es:

 foreach (DataRow r in rows) 

Pero no es difícil imaginar código en el que sería muy útil declarar rows como IEnumerable – código donde se consultaban muchos tipos diferentes de objetos, no era factible colocar la statement de consulta junto a la iteración , y sería útil poder inspeccionar las rows con IntelliSense. Y eso es una cosa, no una cuestión de cómo.

Obtendrá una gran variedad de opiniones sobre esta, desde “use var everywhere” hasta “use solo var con tipos anónimos, donde básicamente tiene que hacerlo”. Me gusta la opinión de Eric Lippert :

Todo el código es una abstracción. ¿Lo que el código “realmente” está haciendo es manipular datos? No. Números? Bits? No. ¿Voltajes? No. ¿Electrones? Sí, pero entender el código a nivel de electrones es una mala idea. El arte de la encoding es descubrir cuál es el nivel correcto de abstracción para el público.

En un lenguaje de alto nivel, siempre existe esta tensión entre QUÉ hace el código (semánticamente) y CÓMO lo logra el código. Los progtwigdores de mantenimiento deben comprender tanto el qué y el cómo si van a tener éxito para realizar cambios.

El objective de LINQ es desestimar masivamente el “cómo” y enfatiza masivamente el “qué”. Al usar una comprensión de consulta, el progtwigdor le dice a la audiencia futura “Creo que no debe saber ni importar exactamente cómo se está calculando este conjunto de resultados, pero debe preocuparse mucho por la semántica del conjunto resultante”. Hacen que el código esté más cerca del proceso de negocio que se está implementando y más lejos de los bits y electrones que lo hacen funcionar.

Los lugareños implícitamente tipeados son solo una pequeña forma en la que puedes restar importancia al cómo y enfatizar el qué. Si eso es lo correcto en un caso particular es una decisión. Así que le digo a la gente que si el conocimiento del tipo es relevante y su elección es crucial para la operación continua del método, entonces no use tipeo implícito. La escritura explícita dice “Te estoy diciendo cómo funciona esto por una razón, presta atención”. La tipificación implícita dice que “no importa un poco si esto es una lista o un cliente [], lo que importa es que se trata de una colección de clientes”.

Personalmente, no suelo usarlo si el tipo no es razonablemente obvio, donde incluyo las consultas LINQ como “razonablemente obvias”. No lo haría por Directory.GetFiles por ejemplo, ya que no es realmente obvio que eso devuelva una string[] lugar de (digamos) un FileInfo[] (o algo completamente diferente) – y eso hace una gran diferencia con lo que hacer luego

Si hay una llamada de constructor en el lado derecho del operador de asignación, es mucho más probable que vaya con var : es evidentemente obvio cuál será el tipo. Esto es particularmente útil con tipos generics complejos, por ejemplo, Dictionary> .

Personalmente, solo uso var en dos lugares:

  1. Con tipos anónimos, es decir. Relacionado con LINQ (donde se requiere var en algunos casos)
  2. Cuando el enunciado declara y construye un tipo específico del mismo tipo

es decir. este es un ejemplo del punto 2:

 var names = new List(); 

Editado : Esto en respuesta a la pregunta de Jon Skeet.

La respuesta anterior fue, de hecho, simplificada. Básicamente, uso var donde el tipo es:

  1. Innecesario saber (no muchos lugares)
  2. Imposible saber (LINQ, tipos anónimos)
  3. De lo contrario, conocido o borrado del código

En el caso de un método de fábrica, donde todo lo que necesitas saber en el lugar donde escribes el código es que el objeto que obtienes es descendiente de algún tipo, y que algún tipo tiene un método de fábrica estático, entonces yo usaría var . Me gusta esto:

 var connection = DatabaseConnection.CreateFromConnectionString("..."); 

El ejemplo anterior es un ejemplo real de mi código. Está claro, al menos para mí y las personas que usan este código, que la conexión es un descendiente de DatabaseConnection, pero el tipo exacto no es necesario ni para entender el código ni para usarlo.

Probé el estilo “use var everywhere” … y he aquí por qué no continué usándolo.

  1. Legibilidad degradada a veces
  2. Límites Intellisense después =
  3. Escribir “var” realmente no era mucho más corto que escribir “int”, “string”, etc., especialmente con intellisense.

Dicho esto, todavía lo uso con LINQ.

Viniendo de la tierra de la progtwigción funcional, donde la inferencia de tipos rige el día, utilizo var para todos los locales siempre que sea posible.

En Visual Studio, si alguna vez se pregunta cuál es el tipo de local, todo lo que tiene que hacer es pasar el mouse sobre él con el mouse.

Esta publicación contiene algunas buenas pautas sobre cuándo usar la interfaz tipo var o los tipos de objetos.

Tiendo a usar var todas partes, pero mis compañeros de trabajo me dijeron: detente, es menos legible para nosotros. Así que ahora uso var solo en tipos anónimos, consultas LINQ y dónde está el constructor en el lado derecho.

Creo que es interesante observar cómo esto generalmente se maneja en Haskell. Gracias al isomorfismo de Curry-Howard , se puede inferir el tipo (más general) de cualquier expresión en Haskell, y, por lo tanto, las declaraciones de tipo no son necesarias en ninguna parte, con algunas excepciones; por ejemplo, a veces deliberadamente desea limitar el tipo a algo más específico de lo que se deduciría.

Por supuesto, lo que se requiere y lo que se recomienda no es lo mismo; en la práctica, la convención parece ser que las definiciones de nivel superior siempre tienen declaraciones de tipo, mientras que las definiciones localizadas tienen las declaraciones de tipo omitidas. Esto parece lograr un buen equilibrio entre la claridad de legibilidad de la definición como un todo, en contraste con la brevedad de legibilidad de las definiciones locales “auxiliares” o “temporales”. Si lo entiendo correctamente, no puedes usar var para las definiciones de “nivel superior” (como un método o función global) en primer lugar, así que supongo que esto se traduce en “usar var cualquier lugar que puedas” en C # world. Por supuesto, escribir ” int ” es el mismo número de teclas que ” var “, pero la mayoría de los ejemplos serán más largos que eso.