سؤال

أحاول أن أفهم دور طريقة GethashCode للواجهة iequalitycomparer.

المثال التالي مأخوذ من MSDN:

using System;
using System.Collections.Generic;
class Example {
    static void Main() {
        try {

            BoxEqualityComparer boxEqC = new BoxEqualityComparer();

            Dictionary<Box, String> boxes = new Dictionary<Box,
                                                string>(boxEqC);

            Box redBox = new Box(4, 3, 4);
            Box blueBox = new Box(4, 3, 4);

            boxes.Add(redBox, "red");
            boxes.Add(blueBox, "blue");

            Console.WriteLine(redBox.GetHashCode());
            Console.WriteLine(blueBox.GetHashCode());
        }
        catch (ArgumentException argEx) {

            Console.WriteLine(argEx.Message);
        }
    }
}

public class Box {
    public Box(int h, int l, int w) {
        this.Height = h;
        this.Length = l;
        this.Width = w;
    }
    public int Height { get; set; }
    public int Length { get; set; }
    public int Width { get; set; }
}

class BoxEqualityComparer : IEqualityComparer<Box> {

    public bool Equals(Box b1, Box b2) {
        if (b1.Height == b2.Height & b1.Length == b2.Length
                            & b1.Width == b2.Width) {
            return true;
        }
        else {
            return false;
        }
    }

    public int GetHashCode(Box bx) {
        int hCode = bx.Height ^ bx.Length ^ bx.Width;
        return hCode.GetHashCode();
    }
}

ألا ينبغي أن يكون تنفيذ طريقة متساوٍ كافيًا لمقارنة كائنين مربعين؟ هذا هو المكان الذي نخبر فيه الإطار القاعدة المستخدمة لمقارنة الكائنات. لماذا هناك حاجة إلى GethashCode؟

شكرًا.

لوسيان

هل كانت مفيدة؟

المحلول

قليلا من الخلفية أولا ...

كل كائن في .NET لديه طريقة متساوية وطريقة gethashCode.

يتم استخدام طريقة Equals لمقارنة كائن واحد بكائن آخر - لمعرفة ما إذا كان الكائنان متكافئين.

تقوم طريقة GethashCode بإنشاء تمثيل صحيح 32 بت للكائن. نظرًا لعدم وجود حد لمقدار المعلومات التي يمكن أن يحتوي عليها الكائن ، يتم مشاركة بعض رموز التجزئة بواسطة كائنات متعددة - وبالتالي فإن رمز التجزئة ليس فريدًا بالضرورة.

القاموس هو هيكل بيانات رائع حقًا يتداول بصمة ذاكرة أعلى مقابل تكاليف ثابتة (أكثر أو أقل) لعمليات إضافة/إزالة/الحصول على. إنه خيار ضعيف للتكرار. داخليًا ، يحتوي القاموس على مجموعة من الدلاء ، حيث يمكن تخزين القيم. عند إضافة مفتاح وقيمة إلى قاموس ، يتم استدعاء طريقة GethashCode على المفتاح. يتم استخدام Hashcode الذي تم إرجاعه لتحديد فهرس الدلو الذي يجب تخزين زوج المفتاح/القيمة.

عندما تريد الوصول إلى القيمة ، يمكنك المرور في المفتاح مرة أخرى. يتم استدعاء طريقة GethashCode على المفتاح ، ويقع الدلو الذي يحتوي على القيمة.

عندما يتم تمرير iequalitycomparer إلى مُنشئ القاموس ، يتم استخدام طرق iequalitycomparer.equals و iequalitycomparer.gethashcode بدلاً من الطرق على الكائنات الرئيسية.

الآن لشرح سبب ضرورة كلتا الطريقتين ، فكر في هذا المثال:

BoxEqualityComparer boxEqC = new BoxEqualityComparer(); 

Dictionary<Box, String> boxes = new Dictionary<Box, string>(boxEqC); 

Box redBox = new Box(100, 100, 25);
Box blueBox = new Box(1000, 1000, 25);

boxes.Add(redBox, "red"); 
boxes.Add(blueBox, "blue"); 

باستخدام طريقة boxequalitycomparer.gethashcode في مثالك ، فإن كلا من هذين المربعين لهما نفس hashcode - 100^100^25 = 1000^1000^25 = 25 - على الرغم من أنهما ليسا نفس الكائن بوضوح. السبب في أنها هي نفس الرمز في هذه الحالة هو أنك تستخدم مشغل^(Bitwise Exclusive-or) So 100^100 يلغي ترك الصفر ، كما يفعل 1000^1000. عندما يكون للكائنين المختلفين نفس المفتاح ، فإننا نسمي هذا التصادم.

عندما نضيف اثنين من أزواج المفتاح/القيمة مع نفس الرمز إلى قاموس ، يتم تخزين كلاهما في نفس الدلو. لذلك عندما نريد استرداد قيمة ، يتم استدعاء طريقة GethashCode على مفتاحنا لتحديد موقع الدلو. نظرًا لوجود أكثر من قيمة واحدة في الدلو ، يكرر القاموس جميع أزواج المفاتيح/القيمة في الدلو الذي يدعو إلى طريقة متساوية على المفاتيح للعثور على الحالة الصحيحة.

في المثال الذي نشرته ، فإن المربعين متكافئان ، وبالتالي فإن طريقة متساوية تُرجع صحيحًا. في هذه الحالة ، يحتوي القاموس على مفتاحين متطابقين ، لذلك يلقي استثناء.

TLDR

لذلك باختصار ، يتم استخدام طريقة GethashCode لإنشاء عنوان حيث يتم تخزين الكائن. لذلك لا يتعين على القاموس البحث عنه. إنه يحسب فقط رمز الهاش ويقفز إلى هذا الموقع. طريقة متساوية هي اختبار أفضل للمساواة ، ولكن لا يمكن استخدامها لرسم خريطة كائن في مساحة العنوان.

امل ان يساعد

نصائح أخرى

GethashCode يستخدم في كولونز القاموس ويخلق التجزئة لتخزين الكائنات فيه. إليك مقالة لطيفة لماذا وكيفية استخدامها iequaltycomparer و GethashCode http://dotnetperls.com/iequalitycomparer

في حين أنه سيكون من الممكن ل Dictionary<TKey,TValue> أن يكون لها GetValue ودعوة طرق مماثلة Equals في كل مفتاح مخزن واحد لمعرفة ما إذا كان يتطابق مع الشخص الذي يتم البحث عنه ، سيكون ذلك بطيئًا للغاية. بدلاً من ذلك ، مثل العديد من المجموعات القائمة على التجزئة ، فإنها تعتمد على GetHashCode لاستبعاد معظم القيم غير المتطابقة بسرعة من النظر. إذا استدعاء GetHashCode على عنصر يتم البحث عنه 42 ، ومجموعة تحتوي على 53،917 عنصرًا ، ولكن الاتصال GetHashCode في 53،914 من العناصر ، أسفرت عن قيمة أخرى غير 42 ، ثم يجب مقارنة 3 عناصر فقط بتلك التي يتم البحث عنها. قد يتم تجاهل 53،914 الآخر بأمان.

سبب أ GetHashCode يتم تضمينه في IEqualityComparer<T> هو السماح بإمكانية أن يرغب مستهلك القاموس في اعتبارها كائنات متساوية عادة ليس النظر في بعضها البعض على قدم المساواة. المثال الأكثر شيوعًا هو المتصل الذي يريد استخدام السلاسل كمفاتيح ولكن استخدام مقارنات غير حساسة للحالة. من أجل جعل هذا العمل بكفاءة ، سيحتاج القاموس إلى الحصول على شكل من أشكال التجزئة التي من شأنها أن تسفر عن نفس القيمة لـ "Fox" و "Fox" ، ولكن نأمل أن تسفر عن شيء آخر لـ "Box" أو "Zebra". منذ GetHashCode الطريقة المدمجة في String لا يعمل بهذه الطريقة ، سيحتاج القاموس إلى الحصول على مثل هذه الطريقة من مكان آخر ، و IEqualityComparer<T> هو المكان الأكثر منطقية لأن الحاجة إلى رمز التجزئة سوف ترتبط بقوة كبيرة مع Equals الطريقة التي تعتبر "Fox" و "Fox" متطابقة مع بعضها البعض ، ولكن ليس إلى "Box" أو "Zebra".

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top