¿Hasta dónde deberían 'var' y el operador de fusión nulo '??' ser entretenido sin obstaculizar la legibilidad?

23

Sé que el título de la pregunta es muy subjetivo, pero ??mis pares me confrontaron con el uso del operador, donde al mismo tiempo no estaba muy contento / cómodo con la aplicación varde un nuevo código.

El argumento dado para usar el ??operador fue, quita la legibilidad en el código.

Mi pregunta es, ¿no sucede lo mismo cuando comienzas a usar var?

Numan
fuente
49
Si un "desarrollador" no puede entender el ??operador de fusión nula después de que se explica, no se debe permitir que se acerque al código de producción.
CaffGeek
12
Sugiero que cambiemos el operador de ?? a IfNullThen. ? puede ser IfSoChoose,: es ElseChoose. + es Agregar. - es Restar, a menos que sea unario, entonces es Negativo. - se divide entre DecrementBeforeUsing y DecrementAfterUsing. En C ++ puedes hacer esto con macros.
Lee Louviere el
77
@ Xaade: Eso es ironía, ¿no? ... ¿Derecha? ... Dios, que sea ironía (y yo soy ateo).
Steven Jeuris
10
@ StevenJeuris Puede ser sarcasmo , pero no es ironía .
Kirk Broadhurst, el
1
@KirkBroadhurst: Estoy corregido , siempre he estado confundiendo a esos dos.
Steven Jeuris

Respuestas:

53

Operador de fusión nula (??)

Personalmente, no veo inconvenientes en el uso de este operador. Considere los siguientes tres ejemplos de código, desde operadores nuevos 'fáciles' hasta 'complejos'.

Sin magia:

bool isNameSet = false;
string name;
if ( isNameSet )
{
    Console.WriteLine( name );
}
else
{
    Console.WriteLine( "No name set." );
}

Operador ternario:

bool isNameSet = false;
string name;
Console.WriteLine( isNameSet ? name : "No name set." );

Fusión nula:

string name = null;
Console.WriteLine( name ?? "No name set." );

La razón por la que se inventaron estos operadores es porque representan operaciones de programación muy comunes . No querer usarlos porque no estás acostumbrado a ellos es solo ser terco . Los idiomas evolucionan, las características evolucionan, ¡aprende a usarlas!

palabra clave var

Tengo una opinión algo diferente sobre la palabra clave var. El tipo de una variable a menudo proporciona información adicional sobre su código. Creo que ocultar el tipo usando la palabra clave var a veces hace que el código sea menos legible. Sabes menos qué esperar sin usar la finalización automática o pasar el cursor sobre los identificadores para ver cuáles son realmente. En mi opinión, esto da como resultado un código que es más lento de leer / escribir.

Utilizo la palabra clave cuando encuentro que el tipo no da mucha información adicional.

  • Principalmente en bucles foreach , que aprendí de Resharper ya que es un escenario allí. La mayoría de las veces, usted sabe qué tipo de colección está atravesando, por lo que sabe que espera artículos de esa colección.
  • Consultas Linq . El resultado de las consultas linq a menudo son tipos genéricos muy complejos. Mostrar este tipo hace más daño que bien.
  • Nombres largos que simplemente se inicializan con su constructor. Ya puedes saber cuál es el tipo mirando el constructor.

Como ejemplo para la última declaración:

ThisIsSomeSpecializedTypeRightHere duplication =
    new ThisIsSomeSpecializedTypeRightHere();
var justAsReadable =
    new ThisIsSomeSpecializedTypeRightHere();  // Less duplication.

// But I still prefer the following ...
int number = 9;
SomeCreatedType foo = Factory.CreateSomeType();
Steven Jeuris
fuente
24
Ese último ejemplo es exactamente cuando la palabra clave var puede sobresalir. Imagine que el código está plagado en todo su código. Factory.CreateSomeTypevuelve IEnumerable<SomeType>. Un día, por cualquier razón, cambia para regresar SomeType[]. Si ha usado var, es solo una recompilación.
pdr
1
Obtuve ese ejemplo al revés y luego fui a buscar comida. Numpty! Un mejor ejemplo sería usar el tuyo. ¿Qué pasa si los Factory.CreateSomeType()cambios devuelven un ISomeType?
pdr
44
@pdr: lo más probable es que la interfaz también haya cambiado, y el comportamiento también debe ajustarse / agregarse. Si es un simple cambio de nombre, por supuesto, tiene un cambio automático de nombre. Si el 'contrato' cambia, prefiero ver que mi código se rompe para poder ver si tengo que ajustar algo o no.
Steven Jeuris
2
Creo que es mucho más probable que si devolver un tipo concreto devuelve una interfaz que solo permita otros tipos concretos con la misma interfaz (de acuerdo con el patrón Factory). Pero si el contrato cambia, entonces su código se romperá, aunque es posible que solo se rompa en unos pocos casos en los que es importante y no en todas partes.
pdr
1
@Tom Hawtin, todos sabemos que es inevitable evitarlo por nullcompleto. Además, cuanto más busco alternativas null, más me doy cuenta de que usar nulles a veces la solución más limpia. Mi ejemplo dado no es tan malo en mi humilde opinión, y considero que es un uso apropiado de tipos anulables.
Steven Jeuris
16

var permite un código menos detallado, lo que aumenta la legibilidad. En mi opinión, la legibilidad no debe medirse por la cantidad de detalles que ve, sino por cuántos detalles están ocultos a primera vista. Además de los ejemplos de Linq, var permite escribir pato a nivel de código fuente, dado el siguiente ejemplo:

...
foreach (var message in messages) {
  var label = Factory.CreateLabel();
  label.Text = message;
  Controls.Add(label);
}
...

¿A quién le importa cuál es el tipo de etiqueta siempre que proporcione la propiedad Text?

Codismo
fuente
Alguien tratando de entender si esto es, por ejemplo, una etiqueta winforms o una etiqueta WPF.
Steven Jeuris
14
@ Steven Jeuris: esa suele ser una información de contexto conocida. Si no, te estás acercando al código de una manera incorrecta.
Codism
¿Alguien que quiere saber si es una etiqueta WPF predeterminada o alguna etiqueta personalizada entonces? :)
Steven Jeuris
14
1. ¿Debería importarle a esa persona, siempre y cuando sea una etiqueta con una propiedad Text? 2. Si este es uno de los raros casos en que REALMENTE TIENE una buena razón para preocuparse, pregunte a Intellisense. 3. Si están editando código en un IDE sin Intellisense, probablemente tengan inconvenientes mucho mayores que 'var' :)
KutuluMike
44
Alguien con un pobre sentido de la abstracción.
Jim Balter
16

No tengo ningún comentario serio sobre el ??operador, ya que nunca he usado mucho un lenguaje con ese operador. En cuanto a var, las personas programan en lenguajes como Ruby, Python, Perl y PHP que tienen tipeo totalmente implícito todo el tiempo. Los nativos de estos idiomas se dan cuenta de que el tipo formal de una variable suele ser un ruido irrelevante. Estás más interesado en lo que puede hacer la variable , es decir, su interfaz estructural / duck.

Del mismo modo, programo principalmente en D. D está estáticamente escrito pero tiene la autopalabra clave, que es equivalente a var. Se considera idiomático usarlo en todas partes a menos que vea una necesidad específica de enfatizar el tipo de algo para el lector o (a través de la conversión implícita) al compilador. Excepto ocasionalmente cuando se usa como un tipo de retorno de función (esto está permitido en D), nunca he encontrado que obstaculice la legibilidad, porque pienso principalmente en términos de interfaces estructurales / de pato, no de tipos formales / nominativos, cuando programo.

Además, en mi humilde opinión el uso en vartodas partes posible es un buen ejemplo de DRY. El tipo de algo debe especificarse en un solo lugar, y luego propagarse automáticamente cuando sea necesario. Si usa vary el tipo formal de la variable necesita cambiar en algún momento, el compilador propagará automáticamente los cambios necesarios en todas partes, siempre que el programa siga siendo de tipo correcto, en lugar de que el programador tenga que cambiar manualmente cada instancia . Esta es una buena cosa (TM).

dsimcha
fuente
13

Creo que esta es una pregunta para el equipo al final. Si no es legible para nadie más en mi equipo, entonces no lo usaré, aunque podría intentarlo un par de veces para convencerlos con ejemplos, o señalando abreviaturas análogas (como + =) que encuentran más legibles.

Sin embargo, si trabajo solo, entonces me parece? y var legible sin límites. Incluso

var a = b ?? c ?? d ?? e ?? "";

es bastante inequívoco para mí

Los operadores ternarios y dynamicson una cuestión diferente, por supuesto.

pdr
fuente
44
Yo usaría 'String.Empty' aquí.
Trabajo
1
@Job, honestamente, yo también. Iba a poner algo en esa cadena, luego no podía pensar en nada :)
pdr
44
var a = b ?? c ?? d ?? e ?? String.Empty ?? "";
Lee Louviere el
2
@Xaade Nunca puedes estar lo suficientemente seguro. Pero realmente, usar String.Empty o "" es una preferencia personal. Yo uso "" porque es más corto ...
Carra
12
@Xaade: si String.Emptyalguna vez regresa null, nos espera muchísimo código roto.
Jesse C. Slicer
10

El argumento dado para usar ?? operador fue, quita la legibilidad en el código.

Pensándolo brevemente, este comentario me dice que la persona que hace el comentario no lo comprende tan bien como debería. Es probable que sea cierto en ciertas situaciones, pero en general, no descarto algo que el equipo de C # obviamente pensó que era lo suficientemente importante como para agregarlo debido a la "legibilidad". Puse esto en la misma categoría de if(boolean_object) frente if(boolean_object == true). Algunas personas argumentan que el segundo es más legible, pero en realidad es solo agregar código adicional para que alguien lo lea / escriba, y en algunas situaciones puede ser más confuso (piense if(boolean_object != false))

Mi pregunta es, ¿no sucede lo mismo cuando comienzas a usar var?

El equipo de C # le ha permitido no definir algo que usted sabe lo que será. A menos que sea absolutamente necesario definir qué va a ser una variable (o es absolutamente importante que un objeto devuelto sea de tipo x, o realmente no sea legible), lo uso var. var x = "MY_STRING";Sé que es una cadena de mirarlo. En verdad, no me importa que sea una cadena siempre que haga lo que necesito que haga. Definir el tipo de variable es para mi beneficio, no el del compilador. Si algo está mal, el compilador me dirá cuándo se ejecuta si tengo el tipo de variable incorrecto.

kemiller2002
fuente
0

los var palabra clave es, en mi opinión, mejor utilizada en las situaciones para las que se introdujo originalmente: consultas LINQ. En estas consultas, el tipo de resultado devuelto a menudo tiene un gran nombre complicado que es difícil de determinar con anticipación y no ayuda a la comprensión del lector de lo que hace su código.

Sin embargo, haciendo var text = "Some text " + variableName + "some more text." es simplemente vago.

EDITAR: @Jorg Saltaste a una respuesta deliberadamente simplista pero no agregaste nada a la discusión. Bien, ¿qué tal esto para un mejor ejemplo? var items = doc.DocumentElement.FirstChild.ChildNodes;Si puedes averiguar el tipo de eso, te daré una cookie.

Josh Earl
fuente
18
Si no puede darse cuenta de que "Some text "es un string, entonces tiene problemas mucho mayores de los que preocuparse que la cantidad de vars en su código.
Jörg W Mittag
3
El problema no es var; El problema es el nombre de la variable "elementos". Si usa un buen nombre de variable, no tiene nada de malo var.
Kyralessa
3
Supongo (sin mirar) que los elementos son una colección de nodos XML, que espero tengan todas las propiedades y métodos de una colección de nodos XML, y eso es realmente todo lo que necesito saber.
KutuluMike
Si necesita saber qué tipo representa la var y no puede saberlo inmediatamente al mirar, simplemente desplace el mouse sobre él. No hace falta mucho para darse cuenta.
scrwtp
1
"es simplemente vago": este no es un argumento en su contra. De hecho, no es nada inteligente.
Jim Balter
0

Tengo un problema fundamental con el uso de var.

En este ejemplo, todo está lado a lado, pero el problema es realmente con grandes soluciones con bibliotecas o proyectos compartidos.

Considera esto:

public MyFirstObject GetMeAnObject() {
    return new MyFirstObject();
}

public void MainProgram() {
    var theObject = GetMeAnObject();
    theObject.PerformOperation();
}

¿Qué sucede si alguien más cambia GetMeAnObject para satisfacer sus necesidades?

public MySecondObject GetMeAnObject() {
    return new MySecondObject();
}

El método MainProgram tendrá un gran error rojo en .PerformOperation (). ¿Que pasó? PerformOperation funcionó perfectamente bien antes. Observamos los métodos en el Objeto y simplemente desapareció sin dejar rastro. Estuvo allí la última vez, y necesitamos ese método. Podría pasar mucho tiempo persiguiendo su cola e intentando descubrir por qué, si MyFirstObject tiene un método llamado PerformOperation, ahora no se puede ver. Todo el mundo "sabe" que GetMeAnObject devuelve un MyFirstObject, por lo que no tiene sentido comprobarlo.

Si hubiera escrito explícitamente theObject, entonces tendría un error Invalid Cast en la línea que llama a GetMeAnObject, y sería muy obvio que GetMeAnObject está devolviendo un tipo que no es lo que espera.

En resumen, la declaración explícita significa que usted sabe lo que significan los errores. Una conversión no válida significa que esperaba un tipo y se devolvió otro tipo. Un miembro no reconocido significa que el miembro no fue reconocido.

Hugh Phoenix-Hulme
fuente
10
Un compañero de trabajo hizo un cambio importante en el código que no está cubierto por las pruebas, ¿y cree que el problema es var? No se puede esperar que el lenguaje proteja contra ese tipo de comportamiento, ¿y si hubieran modificado MyFirstObject directamente? Todavía se habría roto, pero ninguna sintaxis podría haberlo salvado de eso. Consideraría esto una fortaleza de var, incluso: ¿qué pasa si en lugar de devolver MySecondObject ahora devolvieras IMyFirstObject?
Phoshi
2
"Todo el mundo" sabe "que GetMeAnObject devuelve un MyFirstObject, por lo que no tiene sentido comprobarlo". Realmente no puedo pensar en un escenario en la programación en el que realmente dependería de mi memoria de lo que GetMeAnObject si estoy depurando. Si verificara que PerformOperation no está allí, habría visto el código y no, es para otra clase. Si en un IDE la clase mostrara la instancia, miro el tipo de objeto. En realidad, cuando el compilador me dice el error, diría 'clase MySecondObject no tiene ninguna operación PerformOperation'. ¿Cómo es que todo el mundo lo sabe?
Muhammad Alkarouri