gethashcode modificare - Come creo un HashCode in.net(c#)per una stringa che è sicura da memorizzare in un database?





new visual (4)


Dipende da quali proprietà si desidera che hash abbia. Ad esempio, potresti scrivere qualcosa come questo:

public int HashString(string text)
{
    // TODO: Determine nullity policy.

    unchecked
    {
        int hash = 23;
        foreach (char c in text)
        {
            hash = hash * 31 + c;
        }
        return hash;
    }
}

Finché documentate che è così che viene calcolato l'hash, questo è valido. Non è in alcun modo crittograficamente sicuro o qualcosa del genere, ma puoi persistere senza problemi. Due stringhe che sono assolutamente uguali in senso ordinale (cioè senza uguaglianza culturale applicata, esattamente lo stesso carattere per carattere) produrranno lo stesso hash con questo codice.

I problemi arrivano quando ci si basa su hashing non documentato - cioè qualcosa che obbedisce a GetHashCode() ma non è in alcun modo garantito che rimanga lo stesso dalla versione alla versione ... come string.GetHashCode() .

Scrivere e documentare il proprio hash come questo è un po 'come dire: "Questa informazione sensibile è sottoposta a hashing con MD5 (o qualsiasi altra cosa)". Finché si tratta di un hash ben definito, va bene.

EDIT: Altre risposte suggeriscono l'uso di hash crittografici come SHA-1 o MD5. Direi che fino a quando non ci sarà un requisito per la sicurezza crittografica piuttosto che una semplice stabilità, non ha senso passare attraverso la trappola della conversione della stringa in un array di byte e l'hashing. Ovviamente, se l'hash è destinato a essere utilizzato per qualsiasi cosa relativa alla sicurezza, un hash standard del settore è esattamente quello che dovresti raggiungere. Ma questo non è stato menzionato da nessuna parte nella domanda.

Per citare linee guida e regole per GetHashCode di Eric Lippert:

Regola: i consumatori di GetHashCode non possono fare affidamento sulla loro stabilità nel tempo o attraverso le appdomain

Supponiamo che tu abbia un oggetto Cliente che abbia una serie di campi come Nome, Indirizzo e così via. Se si effettuano due tali oggetti con esattamente gli stessi dati in due processi diversi, non è necessario restituire lo stesso codice hash. Se effettui un tale oggetto martedì in un unico processo, spegnilo ed esegui nuovamente il programma mercoledì, i codici hash possono essere diversi.

Questo ha morso le persone in passato. La documentazione per System.String.GetHashCode rileva in modo specifico che due stringhe identiche possono avere codici hash diversi in diverse versioni del CLR e in effetti lo fanno. Non archiviare gli hash delle stringhe nei database e aspettarti che siano sempre gli stessi, perché non lo saranno.

Quindi qual è il modo corretto di creare un codice hash di una stringa che posso memorizzare in un database?

(Per favore dimmi che non sono il primo a lasciare questo bug nel software che ho scritto!)




Ecco una reimplementazione del modo attuale. NET calcola il suo codice hash stringa per i sistemi a 64 bit . Questo non usa puntatori come il vero GetHashCode() , quindi sarà leggermente più lento, ma renderà più resiliente alle modifiche interne alla string , questo darà un codice hash più uniformemente distribuito rispetto alla versione di Jon Skeet che potrebbe risultare migliore tempi di ricerca nei dizionari.

public static class StringExtensionMethods
{
    public static int GetStableHashCode(this string str)
    {
        unchecked
        {
            int hash1 = 5381;
            int hash2 = hash1;

            for(int i = 0; i < str.Length && str[i] != '\0'; i += 2)
            {
                hash1 = ((hash1 << 5) + hash1) ^ str[i];
                if (i == str.Length - 1 || str[i+1] == '\0')
                    break;
                hash2 = ((hash2 << 5) + hash2) ^ str[i+1];
            }

            return hash1 + (hash2*1566083941);
        }
    }
}



La risposta è scrivere semplicemente la tua funzione di hashing. Puoi trovare la fonte per alcuni seguendo i link nei commenti all'articolo che hai postato. Oppure puoi usare una funzione di hash incorporata originariamente pensata per la crittografia (MD5, SHA1, ecc.) E non usare tutti i bit.




Ecco una soluzione.

DateTime dateOfBirth = new DateTime(2000, 4, 18);
DateTime currentDate = DateTime.Now;

int ageInYears = 0;
int ageInMonths = 0;
int ageInDays = 0;

ageInDays = currentDate.Day - dateOfBirth.Day;
ageInMonths = currentDate.Month - dateOfBirth.Month;
ageInYears = currentDate.Year - dateOfBirth.Year;

if (ageInDays < 0)
{
    ageInDays += DateTime.DaysInMonth(currentDate.Year, currentDate.Month);
    ageInMonths = ageInMonths--;

    if (ageInMonths < 0)
    {
        ageInMonths += 12;
        ageInYears--;
    }
}

if (ageInMonths < 0)
{
    ageInMonths += 12;
    ageInYears--;
}

Console.WriteLine("{0}, {1}, {2}", ageInYears, ageInMonths, ageInDays);




c# .net database hashcode gethashcode