Posso dependem dos valores de GetHashCode() para ser consistente?
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.
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.