No se puede usar String.Empty como valor predeterminado para un parámetro opcional

89

Estoy leyendo Effective C # de Bill Wagner. En el artículo 14 - Minimizar la lógica de inicialización duplicada , muestra el siguiente ejemplo del uso de la nueva función de parámetros opcionales en un constructor:

public MyClass(int initialCount = 0, string name = "")

Observe que usó en ""lugar de string.Empty.
Él comenta:

Observará [en un ejemplo anterior] que el segundo constructor especificó "" para el valor predeterminado en el parámetro de nombre , en lugar del más habitual string.Empty. Eso es porque string.Emptyno es una constante en tiempo de compilación. Es una propiedad estática definida en la clase de cadena. Debido a que no es una constante de compilación, no puede usarlo como valor predeterminado para un parámetro.

Si no podemos usar el string.Empty estática en todas las situaciones, ¿no anula eso su propósito? Pensé que lo usaríamos para estar seguros de que tenemos un medio independiente del sistema para referirnos a la cadena vacía. ¿Está mal mi comprensión? Gracias.

ACTUALIZAR
Solo un comentario de seguimiento. Según MSDN:

Cada parámetro opcional tiene un valor predeterminado como parte de su definición. Si no se envía ningún argumento para ese parámetro, se utiliza el valor predeterminado. Los valores predeterminados deben ser constantes.

Entonces no podremos usar System.Environment.NewLineninguno de los dos o usar objetos recién instanciados como valores predeterminados. Todavía no he usado VS2010, ¡y esto es decepcionante!

Mikeyg36
fuente
2
No conozco ninguna diferencia entre cómo se representan las cadenas vacías en diferentes plataformas. No es como una nueva línea.
Tom Cabanski
Bien, estaba pensando eso, entonces, ¿es solo que se ve mejor en el código?
Mikeyg36
1
El CLR y no el 'Sistema' es el factor determinante en cuanto a si "" es una cadena vacía o no. Así que creo que podría asumir con seguridad que "" es una forma independiente del sistema de referirse a una cadena en una implementación CLR compatible.
Chris Taylor
"independiente del sistema"? er, a diferencia del sistema específico ""? (???)
Qwertie
Según MSDN: el valor de este campo es la cadena de longitud cero, "". entonces, obviamente, no tiene nada que ver con la independencia de la plataforma, como muchas personas señalan. ¡Sin embargo, todavía parece que la gente no sabe realmente por qué debería usarse!
Mikeyg36

Respuestas:

65

A partir del compilador de C # 2.0, de String.Emptytodos modos tiene muy poco sentido y, de hecho, en muchos casos es una pesimización, ya que el compilador puede incluir algunas referencias ""pero no puede hacer lo mismo con String.Empty.

En C # 1.1 era útil evitar la creación de muchos objetos independientes que contenían la cadena vacía, pero esos días ya pasaron. ""funciona bien.

Andy Mortimer
fuente
7
Incluso en .NET 1.1 no crearía "muchos" objetos independientes. No puedo recordar los detalles de las diferencias entre 1.1 y 2.0 a este respecto, pero no es como si el internamiento literal de cadenas solo se introdujera en 2.0.
Jon Skeet
Gracias por la aclaración. He echado un vistazo y no he encontrado un buen resumen de los cambios en C # 2.0, aunque estoy seguro de haber leído uno anteriormente. Encontré una respuesta de StackOverflow de 2008 con algunos enlaces a más información técnica. stackoverflow.com/questions/151472/…
Andy Mortimer
1
Le daré un asentimiento a esto, aunque no me gusta decir que no tiene mucho sentido encadenar. Vacío, ya que lo uso bastante. Me parece que se ve más limpio, aunque esa es mi opinión personal. Hay muchos lugares donde no se puede usar string.Empty, y no tengo problemas para usar "" en esos casos
xximjasonxx
14
Descubrí que es mucho más fácil identificar rápidamente una cadena vacía con String.Empty que mirar dos veces "" para asegurarse de que no tenga un apóstrofe o algo así oculto. Sin embargo, +1 para la explicación.
NotMe
11
+1 Chris. También en VS, realmente no puede hacer una búsqueda sobre los usos de "" (aparte de hacer la búsqueda estándar que también traerá todas las coincidencias de texto, incluidos los comentarios y las marcas). Puede hacer una búsqueda sobre usos específicos del código con string.Empty.
MutantNinjaCodeMonkey
53

No hay nada que le impida definir su propia constante para la cadena vacía si realmente desea usarla como un valor de parámetro opcional:

const string String_Empty = "";

public static void PrintString(string s = String_Empty)
{
    Console.WriteLine(s);
}

[Dicho sea de paso, una de las razones para preferir String.Emptymás"" en general, que no se ha mencionado en otras respuestas, es que hay varios caracteres Unicode (carpinteros de ancho cero, etc.) que son efectivamente invisibles a simple vista. Entonces, algo que parece ""no es necesariamente la cadena vacía, mientras que con String.Emptyusted sabe exactamente lo que está usando. Reconozco que esta no es una fuente común de errores, pero es posible.]

Matthew Strawbridge
fuente
2
También hay caracteres identificadores invisibles, por lo que algo que se parece a String_Empty no es necesariamente. El estándar Unicode tiene un capítulo en gran parte ignorado sobre consideraciones de seguridad.
Jim Balter
25

De la pregunta original:

Pensé que lo usaríamos para asegurarnos de que tenemos un medio independiente del sistema para referirnos a la cadena vacía.

¿De qué manera puede variar la cadena vacía de un sistema a otro? ¡Siempre es una cadena sin caracteres! Estaría realmente asustado si alguna vez encontrara una implementación donde se string.Empty == ""devuelva falso :) Esto no es lo mismo que algo comoEnvironment.NewLine .

De la publicación de recompensas de Counter Terrorist:

Quiero String.Empty se puede usar como parámetro predeterminado en la próxima versión de C #. :RE

Bueno, eso ciertamente no va a suceder.

Aunque personalmente también me hubiera gustado un mecanismo de incumplimiento muy diferente, la forma en que funcionan los parámetros opcionales ha sido en .NET desde el principio, y siempre significa incrustar una constante en los metadatos, para que el código de llamada pueda copiar esa constante en la llamada. site si no se proporciona ningún argumento correspondiente.

Con string.Emptyque es realmente inútil - utilizando ""va a hacer lo que quiere; ¿Es tan doloroso usar la cadena literal? (Yo uso el literal en todas partes, nunca lo uso string.Empty, pero ese es un argumento diferente).

Eso es lo que me sorprende de esta pregunta: la queja gira en torno a algo que en realidad no causa un problema real. Es más importante en los casos en los que desea que se calcule el valor predeterminado en el momento de la ejecución porque en realidad podría variar. Por ejemplo, podría imaginar casos en los que desee poder llamar a un método con un DateTimeparámetro y tenerlo predeterminado en "la hora actual". Por el momento, la única solución vagamente elegante que conozco para eso es:

public void RecordTime(string message, DateTime? dateTime = null)
{
    var realDateTime = dateTime ?? DateTime.UtcNow;
}

... pero eso no siempre es apropiado.

En conclusión:

  • Dudo mucho que esto alguna vez sea parte de C #
  • Porque string.Emptyde todos modos no tiene sentido
  • Para otros valores que realmente no siempre tienen el mismo valor, realmente puede ser un dolor
Jon Skeet
fuente
En realidad, esta es una buena forma de solucionar el problema. Lo mismo se puede usar para llevar / establecer otras variables dependientes del dispositivo como Environment.Newline... Lo único que falta en su ejemplo sería una verificación en la variable para nulo, y devolver una excepción al desarrollador diciéndole que si bien es anulable, es no aceptada. if(dateTime == null){ throw new ArgumentException("The dateTime parameter must be set. Nullable type used for device independent variable set.");}o algo así. ¡Pero me gusta mucho esto! ¿Alguna otra advertencia para hacerlo a tu manera?
MaxOvrdrv
@MaxOvrdrv: no quiere que sea nulo para ser un error; el punto es que cuando es nulo, calcula un valor predeterminado. La advertencia es que no permite que se pase nulo como un valor válido en sí mismo.
Jon Skeet
Tienes toda la razón en eso. Culpa mía. - Y sí, esa sería la única salvedad real, ¿no? No es tan malo. De nuevo: ¡me gusta mucho esta solución! :) ¡Gracias por publicarlo! :)
MaxOvrdrv
7

Nunca uso una cuerda Vacío, no puedo ver el sentido de eso. Tal vez lo haga más fácil para las personas que son realmente nuevas en programación, pero dudo que sea útil incluso para eso.

Hans Olsson
fuente
2
Tal vez evite confusión ""y " ", pero no puedo decir que " "sea ​​tan común.
Greg
8
Sugeriría que cualquiera que no pueda notar la diferencia entre esos necesita mejores lentes o reducir la resolución de su pantalla. Tengo mala vista y no recuerdo haber cometido nunca ese error (y tengo que trabajar con mucho código que contiene ambos).
Hans Olsson
2
string.Empty es útil para averiguar la intención exacta del programador. "" no dice nada acerca de la intención, ¿y si la intención del programador fuera inicializar la variable como esta "lol" pero se olvidó ... en este caso hay infinitas posibilidades y cadena, Empty es útil y hace un mejor trabajo
útilBee
4

Creo que la idea detrás de string. Vacío es que mejora la legibilidad. No es como una nueva línea donde hay alguna diferencia entre cómo se representa en las diferentes plataformas. Es una pena que no se pueda usar en un parámetro predeterminado. Sin embargo, no causará ningún problema si realiza la migración entre Windows y algo como Mono en Linux.

Tom Cabanski
fuente
5
Creo que probablemente tengas razón en que el punto es que algunas personas lo consideran String.Emptymás legible. . . personalmente, creo que eso es un poco loco. ""es probablemente la cadena más común que existe y todos la han visto mil millones de veces, entonces, ¿cómo es ilegible? String.Emptyes tan útil como si hubiera un Int32.Zero.
Tim Goodman
3

Como FYI, parece que se impone la misma restricción a los valores pasados ​​a los constructores de atributos: deben ser constantes. Dado que string.empty se define como:

public static readonly string Empty

en lugar de una constante real, no se puede utilizar.

Shawn Eavis
fuente
1

yo suelo string.Empty puramente por legibilidad.

Si alguien más necesita leer / cambiar mi código más tarde, sabrá que tenía la intención de verificar o establecer algo en una cadena vacía. El uso de just a ""veces puede causar errores y confusión porque es posible que me haya olvidado de poner la cadena que quería allí.

Por ejemplo:

if(someString == string.Empty)
{

}

vs

if(someString == "")
{

}

La primera ifdeclaración me parece mucho más deliberada y legible. Sin embargo, debido a que esto es solo una preferencia, realmente no veo el colapso del tren en tener que usar en ""lugar de string.Empty.

lukejkw
fuente
-2

Quizás la mejor solución a este problema sea una sobrecarga de este método, de esta manera:

public static void PrintString() 
{ 
    PrintString(string.Empty);
}
lokum09
fuente
3
¿Cómo es esa respuesta a la pregunta anterior?
Pranav Singh
1
¿Cómo ayuda con los valores predeterminados de los parámetros opcionales?
configuración regional predeterminada