2015-05-26 9 views
6

System.Drawing.Point ha un metodo molto, molto male GetHashCode se avete intenzione di usarlo per descrive 'pixel' in un'immagine/Bitmap: it is just XOR between the X and Y coordinates.sostituto del GetHashCode() Modalità di System.Drawing.Point

Così, per un'immagine con, ad esempio, la dimensione 2000x2000, ha un numero assurdo di colisioni, poiché solo i numeri nella diagonale avranno un hash decente.

È abbastanza facile creare un metodo decente GetHashCode utilizzando la moltiplicazione non selezionata, come alcune persone hanno già menzionato here.

Ma cosa posso fare per utilizzare questo metodo migliorato GetHashCode in un HashSet? So che potrei creare la mia classe/struct MyPoint e implementarla usando questi metodi migliorati, ma poi spezzerei tutti gli altri pezzi di codice nel mio progetto che usano uno System.Drawing.Point.

È possibile "sovrascrivere" il metodo da System.Drawing.Point utilizzando una sorta di metodo di estensione o simile? O per "dire" allo HashSet di utilizzare un'altra funzione invece di GetHashCode?

Attualmente sto utilizzando uno SortedSet<System.Drawing.Point> con un numero personalizzato IComparer<Point> per memorizzare i miei punti. Quando voglio sapere se il set contiene un Punto, chiamo BinarySearch. È più veloce di un metodo HashSet<System.Drawing.Point>.Contains in un set con 10000 colisioni, ma non è veloce quanto lo HashSet con un buon hash.

risposta

10

È possibile creare la propria classe che implementa IEqualityComparer<Point>, quindi assegnare tale classe allo HashSet constructor.

Esempio:

public class MyPointEqualityComparer : IEqualityComparer<Point> 
{ 
    public bool Equals(Point p1, Point p2) 
    { 
     return p1 == p2; // defer to Point's existing operator== 
    } 

    public int GetHashCode(Point obj) 
    { 
     return /* your favorite hashcode function here */; 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     // Create hashset with custom hashcode algorithm 
     HashSet<Point> myHashSet = new HashSet<Point>(new MyPointEqualityComparer()); 

     // Same thing also works for dictionary 
     Dictionary<Point, string> myDictionary = new Dictionary<Point, string>(new MyPointEqualityComparer()); 
    } 
} 
+1

Questo è impressionante! Non ho notato che IEqualityComparer aveva un metodo GetHashCode()! Risposta perfetta! – Trauer