Qual é o uso de System.String.Copy em .NET?
-
21-08-2019 - |
Pergunta
Eu tenho medo que esta é uma pergunta muito boba, mas eu devo estar faltando alguma coisa.
Por que um quer usar String.Copy (string) ?
A documentação diz que o método
Cria uma nova instância da corda com o mesmo valor como uma String especificado.
Uma vez que strings são imutáveis ??em .NET, eu não tenho certeza qual é a vantagem de usar este método, como eu acho que
string copy = String.Copy(otherString);
faria para todos os efeitos práticos parecem produzir o mesmo resultado que
string copy = otherString;
Isto é, exceto por qualquer contabilidade que está acontecendo, eo fato de que a cópia não é ReferenceEquals
para otherString interna, não há diferenças observáveis ??- corda sendo uma classe imutável cuja igualdade é baseado no valor, não a identidade.
(Graças a @ Andrew Hare por apontar que a minha formulação original não foi suficiente precisa para indicar que eu percebi que havia uma diferença entre Copy
ing e não, mas estava preocupado com a percepção de falta de útil diferença.)
É claro que quando passado um argumento null
, Copy lança uma ArgumentNullException
, ea "nova instância" pode consumir mais memória. Este último não parece ser um benefício, e não tenho certeza que o cheque nulo é um bônus grande o suficiente para justificar um método de copiar todo.
Graças.
Solução
Com String.Copy
você está realmente alocar nova memória e copiar os caracteres de uma cadeia para outra; você começa uma nova instância em oposição a ter ambas as variáveis, sendo a mesma instância. Isso pode importa se você usar a corda com código não gerenciado que lida com os locais de memória diretamente e podem sofrer mutações a string.
Outras dicas
String.Copy
retorna uma nova String
e não produz os mesmos resultados que
String copy = otherString;
Tente isto:
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();
}
}
Quando você define test2 = test
estas referências apontam para o mesmo String
. A função Copy
retorna uma nova referência String
que tem as mesmas conteúdo , mas como um objeto diferente na pilha.
Editar: Há um monte de pessoas que são muito chateado que eu não responder à pergunta do OP. Eu acredito que eu fiz responder à pergunta, corrigindo uma premissa errada na própria pergunta. Aqui é um análogo (se não simplista) de perguntas e respostas que esperamos ilustrar meu ponto:
Pergunta:
Eu observei que meu carro tem duas portas, uma de cada lado do carro. Eu acredito que seja verdade que, independentemente de qual porta eu uso I vai acabar sentado no banco do motorista. Qual é o objetivo da outra porta?
Resposta:
Na verdade, não é verdade que se você usar qualquer porta que você vai acabar no banco do motorista. Se você usar a porta do lado do motorista, você vai acabar no banco do motorista e se você usar a porta do lado do passageiro, você vai acabar no banco do passageiro.
Agora, neste exemplo, você poderia argumentar que a resposta não é realmente uma resposta como a pergunta era "o que é o propósito da porta do lado do passageiro?". Mas desde que a pergunta foi totalmente baseado em um equívoco da forma como as portas trabalhou não se segue que a refutação da premissa vai lançar uma nova luz sobre o objetivo da outra porta por dedução?
Aqui está uma peça do puzzle. Ele não explica por que você iria querer fazê-lo, mas não ajudam a explicar a diferença funcional.
Se você fixar a corda utilizando palavras-chave fixed
, o conteúdo seria mutável. Em cima da minha cabeça, eu não consigo pensar em uma situação em que você iria querer fazer isso, mas é possível.
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);
Output:
Jello World
Jello World
Hello World
Uma busca rápida através do BCL for .NET 4.0 mostra que o método string.Copy
é chamado em cerca de meia dúzia de lugares. Os usos cair em cerca nestas categorias:
-
Para interoperabilidade com funções nativas que podem danificar as cordas passados ??para eles. Se você não pode afetar a declaração P / Invoke e você não pode fixar a função que está sendo chamado,
string.Copy
é a melhor escolha. -
Para situações onde a cadeia é modificado no local por motivos de desempenho. Se você precisa converter apenas alguns caracteres para minúsculas em uma potencialmente longa seqüência, a única maneira de fazê-lo sem copiar a cadeia duas vezes e criação de lixo adicional é a mutação-lo.
-
Em locais onde não parece necessário. É bem possível que alguns programadores são mais utilizados para cordas Java ou C ++ e não percebem que copiar uma string em C # raramente é útil.
string a = "abc";
string b = String.Copy(a);
Monitor.Enter(a); // not the same as Monitor.Enter(b);
No entanto
string c = "123";
string d = c;
Monitor.Enter(c); // the same as Monitor.Enter(d);
Como a maneira de alguém se importa, eu acho que ele está lá para ser completo.
Além disso
StringBuilder sb = new StringBuilder(100);
sb.Append("abc");
string a = sb.ToString();
string b = String.Copy(a);
Eu acho a
vai ocupar mais memória RAM, em seguida, b
, como a
aponta para o buffer de tamanho 100 que o StringBuilder
criado. (Olhe para o interior do método StringBuilder.ToString()
)
Eu acho StringBuilder
faz uso de String.Copy()
e fazer parte dos StringBuilder
does .NET framework alterar o conteúdo do string
. Assim, um string
nem sempre é imutável.
Além do que tvanfosson disse (eu não acho que você pode acessar o buffer utilizado por uma corda gerido a partir de código não gerenciado ... Eu sei que seria difícil, pelo menos), eu acredito que pode haver uma diferença se a corda é usada como o objeto para fazer um bloqueio sobre a funcionalidade de vários segmentos.
Por exemplo ...
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
}
}
}
Eu acredito que se os dois métodos de exemplo são executados em paralelo, vão ser de bloqueio do mesmo objecto e, assim, um não será capaz de executar, enquanto a outra está dentro de seu bloco de bloqueio.
No entanto, se você alterá-lo para isto ...
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
}
}
}
Então eu acredito que eles só irá bloquear a execução de outros threads em execução o mesmo método (isto é, quaisquer threads em execução ExampleMethod1 será bloqueado até que cada concluída, mas eles não vão interferir com threads em execução ExampleMethod2).
Não sei se este é um útil diferença, uma vez que existem melhores mecanismos para a sincronização (Eu não acho que cordas de bloqueio é uma idéia muito boa).
string a = "test";
string b = a;
//Object.ReferenceEquals(a,b) is true
a += "more";
//Object.ReferenceEquals(a,b) is now false !
auto-detecção de mudança?
Eu não sei como cordas a ser implementado em .NET, mas acho que Java é uma boa referência.
Em Java, new String (str) também fazer o que String.copy (str); que, alocar uma nova string com o mesmo valor.
O parecer inútil, mas é muito útil para otimização de memória.
cadeia contém um char [] com deslocamento e comprimento na implementação. Se você fizer um algo como um substring, ele não vai fazer uma cópia de memória, mas retornar um mesmo caractere nova partilha instância String []. Em muitos casos, este padrão vai economizar um monte de cópia de memória e alocação. No entanto, se você substring um pequeno pedaço dentro de uma grande cadeia longa. Vai ainda referência à grande char [] até mesmo a cadeia de grandes dimensões originais é capaz de 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
Pode forçar o novo objeto String alocar o seu próprio char [] para evitar escondida memória vazamento / resíduos.