Pergunta

Este trecho de código é de C # in Depth

    static bool AreReferencesEqual<T>(T first, T second)
        where T : class
    {
        return first == second;
    }

    static void Main()
    {
        string name = "Jon";
        string intro1 = "My name is " + name;
        string intro2 = "My name is " + name;
        Console.WriteLine(intro1 == intro2);
        Console.WriteLine(AreReferencesEqual(intro1, intro2));
    }

A saída do código acima é

True 
False

Quando o método principal é alterado para

    static void Main()
    {
        string intro1 = "My name is Jon";
        string intro2 = "My name is Jon";
        Console.WriteLine(intro1 == intro2);
        Console.WriteLine(AreReferencesEqual(intro1, intro2));
    }

A saída do código acima é

True 
True

Não consigo entender por quê?

EDIT: Depois de entender-internar cordas seguintes perguntas não se aplicam.

Como são os parâmetros recebidos na AreReferencesEqual método genérico no segundo trecho de código?

O que muda com o tipo corda quando é concatenado para fazer o operador == não chamar o método Equals sobrecarregada do tipo String?

Foi útil?

Solução

No caso de strings, você provavelmente não pretende usar a igualdade de referência. À igualdade de acesso e da desigualdade no métodos genéricos, a sua melhor aposta é a seguinte:

EqualityComparer<T>.Default.Equals(x,y); // for equality
Comparer<T>.Default.Compare(x,y); // for inequality

i.

static bool AreValuesEqual<T>(T first, T second)
    where T : class
{
    return EqualityComparer<T>.Default.Equals(first,second);
}

Isso ainda usa o Equals sobrecarregado, mas alças nulos etc também. Para a desigualdade, este alças nulos, e ambos IComparable<T> e IComparable.

Para outros operadores, consulte MiscUtil .


Re a questão; no caso de:

    string intro1 = "My name is Jon";
    string intro2 = "My name is Jon";
    Console.WriteLine(intro1 == intro2);
    Console.WriteLine(AreReferencesEqual(intro1, intro2));

Você começa true, true porque o compilador e runtime foi projetado para ser eficiente com cordas; nenhum literais que você usa são "internada" e a mesma instância é usada cada vez em seu AppDomain. O compilador (em vez de tempo de execução) também faz o concat se possível -. I

    string intro1 = "My name is " + "Jon";
    string intro2 = "My name is " + "Jon";
    Console.WriteLine(intro1 == intro2);
    Console.WriteLine(AreReferencesEqual(intro1, intro2));

exatamente o mesmo código como o exemplo anterior. Não há nenhuma diferença em tudo. No entanto, se você forçá-lo a cordas concatenar em tempo de execução, ele assume que eles são susceptíveis de ser de curta duração, por isso são não internados / re-utilizado. Assim, no caso:

    string name = "Jon";
    string intro1 = "My name is " + name;
    string intro2 = "My name is " + name;
    Console.WriteLine(intro1 == intro2);
    Console.WriteLine(AreReferencesEqual(intro1, intro2));

Você tem 4 cordas; "Jon" (internados), "Meu nome é" (internados), e duas instâncias diferentes de "Meu nome é Jon". retornos Daí == verdade e referência igualdade retorna false. Mas o valor-igualdade (EqualityComparer<T>.Default) ainda retornar verdadeiro.

Outras dicas

aprendi uma coisa nova hoje.

Eu acho que Jon disse em uma das perguntas, eu tentei responder.

Quando você constrói uma string usando concatenação, == retornará true para 2 cordas de valor correspondente, mas eles não apontam para a mesma referência (que eu pensei, deve devido a seqüência de internar. Jon apontou essa seqüência internar obras para constantes ou literais).

Na versão genérica, ele está chamando Object.ReferenceEquals (que é diferente do que ==. Em caso de corda, == faz comparação de valor).

Como resultado, o concatenado versão retorna false enquanto as constantes (string literal) versão retorna verdadeiro.

EDIT: Eu acho que Jon deve ser em torno de explicar isso de uma maneira muito melhor :)
Preguiçoso mim, eu comprei o livro, mas ainda têm de começar a fazer isso. : (

Não tem nada a ver com o método genérico, mas a instanciação das cordas

na primeira versão do principal você tem:

string name = "Jon";
string intro1 = "My name is " + name;
string intro2 = "My name is " + name;

que cria 4 cordas. Dois dos quais são constantes de tempo de compilação ou seja, "Jon" e "Meu nome é" no entanto ao inicializar intro1 e intro2 o compilador não pode dizer que o nome é sempre jon e resolve o valor de tempo de execução fazer uma nova seqüência para cada um dos intro1 e intro2.

na segunda versão

string intro1 = "My name is Jon";
string intro2 = "My name is Jon";

você só tem uma corda e isso é uma constante de tempo de compilação: "Meu nome é Jon" e você atribui essa seqüência tanto intro1 e intro2 e é por isso

AreReferencesEqual(intro1, intro2)

retornos falsos no primeiro caso e verdadeiras na segunda

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top