Pregunta

En .NET, ¿cuál es la diferencia entre String.Empty y " " , y son intercambiables, o hay alguna referencia subyacente o problemas de localización en torno a igualdad que String.Empty garantizará que no haya un problema?

¿Fue útil?

Solución

En .NET anterior a la versión 2.0, " " crea un objeto mientras string.Empty no crea ningún objeto ref , lo que hace que string.Empty más eficiente.

En la versión 2.0 y posteriores de .NET, todas las apariciones de " " se refieren al mismo literal de cadena, lo que significa que " " es equivalente a < code> .Empty , pero todavía no tan rápido como .Length == 0 .

.Length == 0 es la opción más rápida, pero .Empty proporciona un código ligeramente más limpio.

Consulte la .NET especificación para obtener más información .

Otros consejos

  

¿cuál es la diferencia entre String.Empty y " " ;, y son   intercambiable

string.Empty es un campo de solo lectura, mientras que " " es una constante de tiempo de compilación. Los lugares donde se comportan de manera diferente son:

Valor predeterminado del parámetro en C # 4.0 o superior

void SomeMethod(int ID, string value = string.Empty)
// Error: Default parameter value for 'value' must be a compile-time constant
{
    //... implementation
}

Expresión de mayúsculas y minúsculas en la declaración de cambio

string str = "";
switch(str)
{
    case string.Empty: // Error: A constant value is expected. 
        break;

    case "":
        break;

}

Argumentos de atributos

[Example(String.Empty)]
// Error: An attribute argument must be a constant expression, typeof expression 
//        or array creation expression of an attribute parameter type

Las respuestas anteriores eran correctas para .NET 1.1 (mire la fecha de la publicación que vincularon: 2003). A partir de .NET 2.0 y versiones posteriores, esencialmente no hay diferencia. El JIT terminará haciendo referencia al mismo objeto en el montón de todos modos.

De acuerdo con la especificación C #, sección 2.4.4.5: http://msdn.microsoft.com/en-us/ library / aa691090 (VS.71) .aspx

  

Cada literal de cadena no necesariamente da como resultado una nueva instancia de cadena. Cuando dos o más literales de cadena que son equivalentes de acuerdo con el operador de igualdad de cadena (Sección 7.9.7) aparecen en el mismo ensamblaje, estos literales de cadena se refieren a la misma instancia de cadena.

Alguien incluso menciona esto en los comentarios de la publicación de Brad Abram

En resumen, el resultado práctico de " " vs. String. Vacío es nulo. El JIT lo resolverá al final.

He descubierto, personalmente, que el JIT es mucho más inteligente que yo, por lo que trato de no ser demasiado inteligente con optimizaciones de microcompiladores como esa. El JIT se desplegará para bucles (), eliminará código redundante, métodos en línea, etc. mejor y en momentos más apropiados de lo que yo o el compilador de C # podríamos anticipar de antemano. Deje que el JIT haga su trabajo :)

String.Empty es un campo readonly mientras que " " es un const . Esto significa que no puede usar String.Empty en una instrucción de cambio porque no es una constante.

Otra diferencia es que String.Empty genera un código CIL más grande. Mientras que el código para hacer referencia a " " y String.Empty tiene la misma longitud, el compilador no optimiza la concatenación de cadenas (vea publicación de blog ) para String. Argumentos vacíos. Las siguientes funciones equivalentes

string foo()
{
    return "foo" + "";
}
string bar()
{
    return "bar" + string.Empty;
}

generar esta IL

.method private hidebysig instance string foo() cil managed
{
    .maxstack 8
    L_0000: ldstr "foo"
    L_0005: ret 
}
.method private hidebysig instance string bar() cil managed
{
    .maxstack 8
    L_0000: ldstr "bar"
    L_0005: ldsfld string [mscorlib]System.String::Empty
    L_000a: call string [mscorlib]System.String::Concat(string, string)
    L_000f: ret 
}

Las respuestas anteriores son técnicamente correctas, pero lo que realmente desea utilizar, para una mejor legibilidad del código y la menor posibilidad de una excepción es String.IsNullOrEmpty (s)

Tiendo a usar String.Empty en lugar de " " por una razón simple, pero no obvia: " & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; & # 65279; " y " " NO son lo mismo, el primero tiene 16 caracteres de ancho cero. Obviamente, ningún desarrollador competente va a poner caracteres de ancho cero en su código, pero si llegan allí, puede ser una pesadilla de mantenimiento.

Notas:

Use String.Empty en lugar de "".

  

Esto es más por velocidad que por uso de memoria, pero es un consejo útil. los    " " es un literal, por lo que actuará como un literal: en el primer uso es   creado y para los siguientes usos se devuelve su referencia. Solo uno   La instancia de " " se almacenará en la memoria sin importar cuántas veces   úsalo! No veo ninguna penalización de memoria aquí. El problema es que   cada vez que se usa " " , se ejecuta un ciclo de comparación para verificar si    " " ya está en el grupo interno. En el otro lado, String.Empty   es una referencia a un " " almacenado en la zona de memoria de .NET Framework .    String.Empty apunta a la misma dirección de memoria para VB.NET y C #   aplicaciones. Entonces, ¿por qué buscar una referencia cada vez que necesita " "   cuando tienes esa referencia en String.Empty ?

Referencia: String.Empty vs " "

String.Empty no crea un objeto mientras que " " hace. La diferencia, como se señaló aquí , es trivial, sin embargo.

Todas las instancias de " " son el mismo literal de cadena interno (o deberían serlo). Por lo tanto, realmente no lanzará un nuevo objeto en el montón cada vez que use " " pero solo creando una referencia al mismo objeto interno. Habiendo dicho eso, prefiero string. Vacío. Creo que hace que el código sea más legible.

string mystring = "";
ldstr ""

ldstr empuja una nueva referencia de objeto a un literal de cadena almacenado en los metadatos.

string mystring = String.Empty;
ldsfld string [mscorlib]System.String::Empty

ldsfld inserta el valor de un campo estático en la pila de evaluación

Tiendo a usar String.Empty en lugar de " " porque en mi humilde opinión es más claro y menos VB-ish.

En este punto de vista desde el punto de vista de Entity Framework: EF versiones 6.1.3 parece tratar String.Empty y " " diferente al validar.

string.Empty se trata como un valor nulo para fines de validación y arrojará un error de validación si se usa en un campo Requerido (atribuido); donde como " " pasará la validación y no arrojará el error.

Este problema puede resolverse en EF 7+. Referencia: - https://github.com/aspnet/EntityFramework/issues/2610 ).

Editar: [Obligatorio (AllowEmptyStrings = true)] resolverá este problema, permitiendo que string.Empty se valide.

Dado que String.Empty no es una constante de tiempo de compilación, no puede usarlo como valor predeterminado en la definición de funciones.

public void test(int i=0,string s="")
    {
      // Function Body
    }
  

Eric Lippert escribió (17 de junio de 2013):
" El primer algoritmo en el que trabajé en el compilador de C # fue el optimizador que maneja las concatenaciones de cadenas. Desafortunadamente no logré portar estas optimizaciones al código base de Roslyn antes de irme; ¡espero que alguien llegue a eso! "

Estos son algunos resultados de Roslyn x64 a partir de enero de 2019. A pesar de las observaciones consensuadas de las otras respuestas en esta página, no me parece que el JIT x64 actual esté tratando todos estos casos idénticamente, cuando todo está dicho y hecho.

Tenga en cuenta en particular, sin embargo, que solo uno de estos ejemplos en realidad termina llamando a String.Concat , y supongo que eso es por razones oscuras de corrección (en lugar de una supervisión de optimización). Las otras diferencias parecen más difíciles de explicar.


predeterminado (Cadena) & nbsp; + & nbsp; {default (String), & nbsp; " ;, & nbsp; String.Empty}

static String s00() => default(String) + default(String);
    mov  rax,[String::Empty]
    mov  rax,qword ptr [rax]
    add  rsp,28h
    ret

static String s01() => default(String) + "";
    mov  rax,[String::Empty]
    mov  rax,qword ptr [rax]
    add  rsp,28h
    ret

static String s02() => default(String) + String.Empty;
    mov  rax,[String::Empty]
    mov  rax,qword ptr [rax]
    mov  rdx,rax
    test rdx,rdx
    jne  _L
    mov  rdx,rax
_L: mov  rax,rdx
    add  rsp,28h
    ret

" " & nbsp; + & nbsp; {default (String), & nbsp; " ;, & nbsp; String.Empty}

static String s03() => "" + default(String);
    mov  rax,[String::Empty]
    mov  rax,qword ptr [rax]
    add  rsp,28h
    ret

static String s04() => "" + "";
    mov  rax,[String::Empty]
    mov  rax,qword ptr [rax]
    add  rsp,28h
    ret

static String s05() => "" + String.Empty;
    mov  rax,[String::Empty]
    mov  rax,qword ptr [rax]
    mov  rdx,rax
    test rdx,rdx
    jne  _L
    mov  rdx,rax
_L: mov  rax,rdx
    add  rsp,28h
    ret

String.Empty & nbsp; + & nbsp; {default (String), & nbsp; " ;, & nbsp; String.Empty}

static String s06() => String.Empty + default(String);
    mov  rax,[String::Empty]
    mov  rax,qword ptr [rax]
    mov  rdx,rax
    test rdx,rdx
    jne  _L
    mov  rdx,rax
_L: mov  rax,rdx
    add  rsp,28h
    ret

static String s07() => String.Empty + "";
    mov  rax,[String::Empty]
    mov  rax,qword ptr [rax]
    mov  rdx,rax
    test rdx,rdx
    jne  _L
    mov  rdx,rax
_L: mov  rax,rdx
    add  rsp,28h
    ret

static String s08() => String.Empty + String.Empty;
    mov  rcx,[String::Empty]
    mov  rcx,qword ptr [rcx]
    mov  qword ptr [rsp+20h],rcx
    mov  rcx,qword ptr [rsp+20h]
    mov  rdx,qword ptr [rsp+20h]
    call F330CF60                 ; <-- String.Concat
    nop
    add  rsp,28h
    ret


Detalles de la prueba

Microsoft (R) Visual C# Compiler version 2.10.0.0 (b9fb1610)
AMD64 Release
[MethodImpl(MethodImplOptions.NoInlining)]
'SuppressJitOptimization' = false

Cuando escanea visualmente el código, " " aparece coloreado de la misma manera que las cadenas están coloreadas. string.Empty se parece a un acceso regular de miembro de clase. Durante una mirada rápida, es más fácil detectar " " o intuir el significado.

Encuentra las cadenas (la coloración de desbordamiento de pila no está ayudando exactamente, pero en VS esto es más obvio):

var i = 30;
var f = Math.Pi;
var s = "";
var d = 22.2m;
var t = "I am some text";
var e = string.Empty;

Todos aquí dieron una buena aclaración teórica. Tuve una duda similar. Así que probé una codificación básica. Y encontré una diferencia. Aquí está la diferencia.

string str=null;
Console.WriteLine(str.Length);  // Exception(NullRefernceException) for pointing to null reference. 


string str = string.Empty;
Console.WriteLine(str.Length);  // 0

Entonces parece '' Nulo '' significa absolutamente nulo & amp; " String.Empty " significa que contiene algún tipo de valor, pero está vacío.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top