2009-02-06 7 views
50

Me temo que esta es una pregunta muy tonta, pero me falta algo.¿Cuál es el uso de System.String.Copy en .NET?

¿Por qué podría uno querer usar String.Copy(string)?

La documentación dice que el método

crea una nueva instancia de la cadena con el mismo valor que una cadena especificada.

Dado que las cadenas son inmutables en .NET, no estoy seguro de cuál es la ventaja de utilizar este método, ya que me parece que

string copy = String.Copy(otherString); 
haría

a todos los efectos prácticos parecen producir la misma como resultado

string copy = otherString; 

es decir, a excepción de lo que sea contabilidad interna que está pasando, y el hecho de que la copia no es ReferenceEquals a otherString, no hay diferencias observables - cadena ser una clase inmutable cuya igualdad se basa en el valor, no en la identidad. (Gracias a @ Andrew Hare por señalar que mi redacción original no era lo suficientemente precisa para indicar que me di cuenta de que había una diferencia entre Copy ING y no, pero estaba preocupado por la aparente falta de utilidad diferencia).

Por supuesto, cuando se pasa un argumento null, Copiar arroja un ArgumentNullException, y la "nueva instancia" podría consumir más memoria. Esto último no parece ser un beneficio, y no estoy seguro de que el cheque nulo sea una bonificación lo suficientemente grande como para justificar un método completo de Copia.

Gracias.

+1

bien, las preguntas tontas tienen un montón de votos votados ,, – TarunG

Respuesta

32

Con String.Copy en realidad está asignando nueva memoria y copiando los caracteres de una cadena a otra; obtienes una instancia completamente nueva en lugar de tener ambas variables siendo la misma instancia. Esto puede importar si usa la cadena con código no administrado que trata directamente con las ubicaciones de memoria y puede mutar la cadena.

+0

Esa fue mi suposición. Sería extraño como el infierno si el texto en toda la aplicación comienza a cambiar aleatoriamente ... – Will

+2

Si bien esto es lo primero que me vino a la mente, parece un error esperando a suceder, si estás interpretando interoperabilidad con un código no administrado que está cambiando una cadena, probablemente debería usar un StringBuilder en su lugar. –

+2

Suena como un patrón de error si intentas modificar un objeto inmutable. –

19

String.Copy devuelve una nueva String y no cede los mismos resultados que

String copy = otherString; 

Prueba esto:

using System; 

class Program 
{ 
    static void Main() 
    { 
     String test = "test"; 
     String test2 = test; 
     String test3 = String.Copy(test); 

     Console.WriteLine(Object.ReferenceEquals(test, test2)); 
     Console.WriteLine(Object.ReferenceEquals(test, test3)); 

     Console.ReadLine(); 
    } 
} 

Al configurar test2 = test estas referencias apuntan a la misma String. La función Copy devuelve una nueva referencia String que tiene el mismo contenido pero como un objeto diferente en el montón.


Editar: Hay una gran cantidad de gente que son bastante molesto que no contesté la pregunta del PO. Creo que respondí la pregunta al corregir una premisa incorrecta en la pregunta misma. Aquí se presenta una (si no simplificado) preguntas y respuestas análogas que se espera ilustrar mi punto:

Pregunta:

he observado que mi coche tiene dos puertas, una a cada lado del coche . Creo que es cierto que independientemente de la puerta que use, terminaré sentado en el asiento del conductor. ¿Cuál es el propósito de la otra puerta?

Respuesta:

en realidad no es cierto que si se utiliza cualquiera de las puertas que va a terminar en el asiento del conductor. Si usa la puerta del lado del conductor, terminará en el asiento del conductor y si usa la puerta del lado del pasajero terminará en el asiento del pasajero.

Ahora, en este ejemplo, podría argumentar que la respuesta no es realmente una respuesta, ya que la pregunta era "¿cuál es el propósito de la puerta lateral del pasajero?". Pero dado que esa pregunta se basaba completamente en un concepto erróneo de cómo funcionaban las puertas, ¿no se deduce que la refutación de la premisa arrojará nueva luz sobre el propósito de la otra puerta por deducción?

+0

La pregunta no era "¿Qué es lo que hace" sino "¿Por qué la usaría?" –

+0

Creo que el punto fue:" ¿para qué sirve duplicar información inmutable? "En lugar de volver a usarla. – PhiLho

+0

Toda la pregunta se basaba en la falsa premisa de que " cadena uno = String.Copia (dos); " y "string one = two;" son declaraciones equivalentes. Simplemente estaba señalando que el póster era incorrecto. –

6
string a = "abc"; 
string b = String.Copy(a); 

Monitor.Enter(a); // not the same as Monitor.Enter(b); 

Sin embargo

string c = "123"; 
string d = c; 
Monitor.Enter(c); // the same as Monitor.Enter(d); 

En cuanto a manera de que alguien le importa, creo que está ahí para lo completo.


también

StringBuilder sb = new StringBuilder(100); 
sb.Append("abc"); 
string a = sb.ToString(); 
string b = String.Copy(a); 

creo a ocupará más memoria RAM entonces b, como a puntos en el búfer de tamaño 100 que el StringBuilder creado. (Ver el interior del método StringBuilder.ToString())


Creo StringBuilder hace uso de String.Copy() y ser parte del marco .NET StringBuilder hace cambiar el contenido de la string. Entonces, string no siempre es inmutable.

+0

No es necesario que StringBuilder modifique alguna vez una cadena.Internamente, podría usar una lista que crecería de manera eficiente en tamaño, y luego el método ToString asignaría una cadena del contenido de la lista. –

0
string a = "test"; 
string b = a; 
//Object.ReferenceEquals(a,b) is true 
a += "more"; 
//Object.ReferenceEquals(a,b) is now false ! 

¿detección de cambio automático?

+3

No, agregar a la cadena crea una nueva instancia de una cadena (ya que las cadenas son inmutables). Después de agregar "a" apuntará a otra instancia. – edgi

-1

No estoy seguro de cómo se implementa String en .NET, pero creo que Java es una buena referencia.

En Java, el nuevo String (str) también hace lo que String.copy (str); hacer, asignar una nueva cadena con el mismo valor.

Parece inútil, pero es muy útil en la optimización de la memoria.

Cadena contiene un carácter [] con desplazamiento y longitud en la implementación. Si hace algo así como una subcadena, no hará una copia de memoria sino que devolverá una nueva instancia de String compartiendo el mismo carácter []. En muchos casos, este patrón ahorrará una gran cantidad de copia y asignación de memoria. Sin embargo, si subcadenas una pequeña pieza dentro de una cadena larga larga. Seguirá referenciando a char grande [] incluso la cadena grande original puede ser GC.

String longString = // read 1MB text from a text file 
String memoryLeak = largeString.substring(100,102); 
largeString=null; 
// memoryLeak will be sized 1MB in the memory 
String smaller = new String(largeString.substring(100,102)); 
// smaller will be only few bytes in the memory 

Se puede forzar al nuevo objeto String asignar su propio char [] para evitar fugas de memoria oculta/residuos.

+0

Así no es como funciona. Solo suponiendo que .NET tenga la misma implementación que Java tampoco está bien. Además de eso, la respuesta no tiene nada que ver con la pregunta. ¿Qué sucede cuando .Substring (100, 102): se crea una nueva cadena con longitud 102 que contiene caracteres 100 ... 201 –

1

Además de lo que dijo tvanfosson (no creo que pueda acceder al búfer utilizado por una cadena administrada desde un código no administrado ... Sé que sería difícil, al menos), creo que puede haber una diferencia si la cadena se utiliza como el objeto para hacer un bloqueo en la funcionalidad multiproceso.

Por ejemplo ...

using System; 

public class Class1 
{ 
    string example1 = "example"; 
    string example2 = example1; 

    public void ExampleMethod1() 
    { 
     lock (example1) 
     { 
      Console.WriteLine("Locked example 1"); 
      //do stuff... 
     } 
    } 

    public void ExampleMethod2() 
    { 
     lock (example2) 
     { 
      Console.WriteLine("Locked example 2"); 
      //do stuff 
     } 
    } 
} 

Creo que si los dos métodos de ejemplo se ejecutan en paralelo, van a estar bloqueando el mismo objeto y por lo tanto no se podrán ejecutar, mientras que el otro es el interior de su bloque de bloqueo.

Sin embargo, si lo cambia a esto ...

using System; 

public class Class1 
{ 
    string example1 = "example"; 
    string example2 = string.Copy(example1); 

    public void ExampleMethod1() 
    { 
     lock (example1) 
     { 
      Console.WriteLine("Locked example 1"); 
      //do stuff... 
     } 
    } 

    public void ExampleMethod2() 
    { 
     lock (example2) 
     { 
      Console.WriteLine("Locked example 2"); 
      //do stuff 
     } 
    } 
} 

entonces creo que sólo bloquear la ejecución de otros subprocesos ejecutando el mismo método (es decir, todos los hilos de ejecución ExampleMethod1 se bloquearán hasta que cada uno termina, pero no interferirán con los hilos que ejecutan ExampleMethod2).

No estoy seguro de que esto sea útil diferencia, ya que hay mejores mecanismos para la sincronización (no creo que el bloqueo de cadenas sea una muy buena idea).

13

Aquí hay una pieza del rompecabezas. No explica por qué querrías hacerlo, pero ayuda a explicar una diferencia funcional.

Si pincha la cadena con la palabra clave fixed, los contenidos serían mutables. Fuera de mi cabeza, no puedo pensar en una situación en la que te gustaría hacer esto, pero es posible.

string original = "Hello World"; 
string refCopy = original; 
string deepCopy = String.Copy(original); 

fixed(char* pStr = original) 
{ 
    *pStr = 'J'; 
} 

Console.WriteLine(original); 
Console.WriteLine(refCopy); 
Console.WriteLine(deepCopy); 

Salida:

Jello World 
Jello World 
Hello World 
+0

Eso es cringeworthy y horrible. +1 para el ejemplo. –

+0

fantástica respuesta. – Kalyan

5

Una búsqueda rápida a través de la BCL para .NET 4.0 muestra que el método se llama string.Copy en alrededor de una media docena de lugares. Los usos se encuentran aproximadamente en estas categorías:

  1. Para la interoperabilidad con funciones nativas que pueden dañar las cuerdas que se les pasan. Si no puede afectar la declaración de P/Invoke y no puede reparar la función a la que se llama, string.Copy es la mejor opción.

  2. En situaciones en las que la cuerda se modifica in situ por motivos de rendimiento. Si necesita convertir solo unos pocos caracteres en minúsculas en una cadena potencialmente larga, la única forma de hacerlo sin copiar la cadena dos veces y creando basura adicional es mutarla.

  3. En lugares donde no parece necesario. Es bastante posible que algunos programadores estén más acostumbrados a las cadenas Java o C++ y no se den cuenta de que copiar una cadena en C# rara vez es útil.

Cuestiones relacionadas