Pergunta

É o valor de retorno de GetHashCode() garantido para ser consistente, assumindo o mesmo valor de seqüência de caracteres está sendo usado?(C#/ASP.NET)

Eu enviei o meu código para um servidor de hoje e para minha surpresa eu tinha para reindexar alguns dados porque o meu servidor (win2008 64-bit) estava retornando valores diferentes em relação ao meu computador da área de trabalho.

Foi útil?

Solução

Se eu não estou enganado, GetHashCode é consistente dado o mesmo valor, mas NÃO é garantido para ser consistente em todas as diferentes versões do framework.

A partir do MSDN docs na Cadeia.GetHashCode():

O comportamento de GetHashCode, é dependente da sua implementação, o que pode alterar de uma versão do common language runtime para outro.Uma razão para isso pode acontecer é para melhorar o desempenho de GetHashCode.

Outras dicas

Eu tive um problema semelhante, onde eu preenchida uma tabela de banco de dados com informações de que era dependente de Seqüência de caracteres.GetHashCode (Não é a melhor idéia) e quando eu atualizei o servidor que eu estava trabalhando em x64 notei que os valores que eu estava ficando de Seqüência de caracteres.GetHashCode eram inconsistentes com o que já estava na mesa.A minha solução foi usar a minha própria versão de GetHashCode, que retorna o mesmo valor de Seqüência de caracteres.GetHashCode em um x 86-quadro.

Aqui está o código, não se esqueça de compilar com "Permitir que o código não seguro":

    /// <summary>
    /// Similar to String.GetHashCode but returns the same as the x86 version of String.GetHashCode for x64 and x86 frameworks.
    /// </summary>
    /// <param name="s"></param>
    /// <returns></returns>
    public static unsafe int GetHashCode32(string s)
    {
        fixed (char* str = s.ToCharArray())
        {
            char* chPtr = str;
            int num = 0x15051505;
            int num2 = num;
            int* numPtr = (int*)chPtr;
            for (int i = s.Length; i > 0; i -= 4)
            {
                num = (((num << 5) + num) + (num >> 0x1b)) ^ numPtr[0];
                if (i <= 2)
                {
                    break;
                }
                num2 = (((num2 << 5) + num2) + (num2 >> 0x1b)) ^ numPtr[1];
                numPtr += 2;
            }
            return (num + (num2 * 0x5d588b65));
        }
    }

A implementação é dependente da versão do framework, mas também depende do arquitetura.A implementação de seqüência de caracteres.GetHashCode() é diferentes nas versões x86 e x64 do quadro, mesmo se eles tiverem o mesmo número de versão.

Gostaria de saber se existem diferenças entre a versão de 32-bit e 64-bit sistemas operacionais, porque estou certo de que tanto o meu servidor e o computador de casa estão executando a mesma versão .NET

Eu estava sempre cansado de usar GetHashCode(), pode ser uma boa idéia para mim simplesmente de papel o meu próprio algoritmo de hash.Bem, pelo menos eu acabei de escrever uma rápida re-índice .página aspx por causa disso.

Você está executando o Win2008 x86 como o seu ambiente de trabalho?Porque Win2008 inclui a versão 2.0.50727.1434, que é uma versão atualizada de 2.0 incluído em Vista RTM.

O que nós fizemos notar, no entanto, quando um objeto está em um hash de coleção objeto (uma tabela de hash, um dicionário etc), quando 2 não são objetos únicos mas a sua hashcodes são, o hashcode é usada apenas como uma primeira opção de pesquisa, se existem não-exclusivo códigos de hash a ser utilizado, o operador de igualdade é sempre utilizado como um cair de volta para detirmine igualdade.

Esta é a forma de hash pesquisas de trabalho, certo?Cada segmento contém uma lista de itens de ter o mesmo código hash.

Então, para encontrar o item correto, sob estas condições, uma pesquisa linear usando o valor de comparação de igualdade ocorre.

E se o hash de implementação alcança boa distribuição, esta pesquisa não é necessário, por exemplo, um item por balde.

É o meu entendimento está correto?

Não uma resposta direta à sua pergunta, que Jonas tem respondido bem, no entanto, isso pode ser de ajuda se você está preocupado com o teste de igualdade de hashes

A partir de nossos testes, dependendo do que você está exigindo com hashcodes, em C#, hashcodes não precisa ser exclusivo para a Igualdade de operações.Como um exemplo, considere o seguinte:

Tivemos um requisito para sobrecarga de operador é igual, e, portanto, a função GetHashCode de nossos objetos como eles se tornaram voláteis e sem monitoração de estado, e sourcing-se diretamente a partir de dados, por isso em um lugar do aplicativo, nós necessárias para assegurar que um objeto poderia ser visto como igual a outro objeto se ele foi originado a partir dos mesmos dados, não apenas se foi a mesma referência.A nossa única de dados identificadores são Guids.

O operador é igual a foi fácil para atender como foi verificado no Guid do registro (depois de verificar nulo).

Infelizmente o HashCode tamanho de dados (sendo um int) depende do sistema operacional e, em nossa versão de 32 bits do sistema, o hashcode seria de 32 bits.Matematicamente, quando é substituir a função GetHashCode, é impossível gerar um único hashcode a partir de um guid que é maior do que 32 bits (olha a conversar, como você traduzir uma versão de 32 bit inteiro em um guid?).

Fizemos alguns testes, onde tomou o Guid como uma seqüência de caracteres e devolvido o HashCode do Guid, o que quase sempre retorna um identificador exclusivo em nossos testes, mas não sempre.

O que nós fizemos notar, no entanto, quando um objeto está em um hash de objeto de coleção (um hashtable, um dicionário, etc.), quando 2 objetos não são únicas, mas o seu hashcodes são, o hashcode é usado apenas como uma primeira opção de pesquisa, se houver não-exclusivo códigos de hash a ser utilizado, o operador de igualdade é sempre utilizado como um cair de volta para detirmine igualdade.

Como eu disse, isso pode ou não ser relevantes para a sua situação, mas se for é uma dica prática.

ATUALIZAÇÃO

Para demonstrar, temos uma Hashtable:

Chave:Objeto de Um (Hashcode 1), Objeto de valor A1

Chave:Objeto B (Hashcode 1), Objeto de valor B1

Chave:Objeto de C (Hashcode 1), Objeto de valor C1

Chave:o Objeto D (Hashcode 2), Objeto de valor D1

Chave:Objeto E (Hashcode 3), do valor Objeto E1

Quando eu chamo o hashtable para o objeto com a chave do Objeto A, o objeto A1 será devolvido após 2 etapas, uma chamada para o hashcode 1 e, em seguida, uma verificação de igualdade na tecla objeto como não existe uma chave única com o hashcode 1

Quando eu chamo o hashtable para o objeto com a chave do Objeto D, o objeto D1 será devolvida após a 1 etapa, uma pesquisa de hash

    /// <summary>
    /// Default implementation of string.GetHashCode is not consistent on different platforms (x32/x64 which is our case) and frameworks. 
    /// FNV-1a - (Fowler/Noll/Vo) is a fast, consistent, non-cryptographic hash algorithm with good dispersion. (see http://isthe.com/chongo/tech/comp/fnv/#FNV-1a)
    /// </summary>
    private static int GetFNV1aHashCode(string str)
    {
        if (str == null)
            return 0;
        var length = str.Length;
        // original FNV-1a has 32 bit offset_basis = 2166136261 but length gives a bit better dispersion (2%) for our case where all the strings are equal length, for example: "3EC0FFFF01ECD9C4001B01E2A707"
        int hash = length;
        for (int i = 0; i != length; ++i)
            hash = (hash ^ str[i]) * 16777619;
        return hash;
    }

Esta implementação pode ser mais lento do que o inseguros uma postado antes.Mas muito mais simples e seguro.

Eu teria que Dizer que...você não pode confiar nele.Por exemplo, se eu executar arquivo1 através de c#'s hash md5 código e copiar nd colar o mesmo arquivo para uma nova pasta...o código hash sair diferente, difícil mesmo é ele mesmo arquivo.Evidentemente que o mesmo .net versão, mesmo tudo.A única coisa que mudou foi o caminho.

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