যখন সমান পদ্ধতিটি ওভাররাইড হয় তখন গেটহ্যাশকোডকে ওভাররাইড করা কেন গুরুত্বপূর্ণ?


1444

নিম্নলিখিত ক্লাস দেওয়া

public class Foo
{
    public int FooId { get; set; }
    public string FooName { get; set; }

    public override bool Equals(object obj)
    {
        Foo fooItem = obj as Foo;

        if (fooItem == null) 
        {
           return false;
        }

        return fooItem.FooId == this.FooId;
    }

    public override int GetHashCode()
    {
        // Which is preferred?

        return base.GetHashCode();

        //return this.FooId.GetHashCode();
    }
}

আমি Equalsপদ্ধতিটি ওভাররাইড করেছি কারণ এস টেবিলের Fooজন্য একটি সারি উপস্থাপন করে Foo। ওভাররাইড করার জন্য পছন্দসই পদ্ধতি কোনটি GetHashCode?

ওভাররাইড করা কেন গুরুত্বপূর্ণ GetHashCode?


36
সংঘর্ষের কারণে, বিশেষত অভিধানগুলি ব্যবহার করার সময় উভয় সমান এবং গেটাহকোড কার্যকর করা গুরুত্বপূর্ণ implement যদি দুটি অবজেক্ট একই হ্যাশকোড দেয়, তবে তারা শৃঙ্খলা সহ অভিধানে সন্নিবেশ করানো হয়। আইটেমটি অ্যাক্সেস করার সময় সমান পদ্ধতি ব্যবহৃত হয়।
দার্থভেদার

উত্তর:


1318

হ্যাঁ, আপনার আইটেমটি অভিধানে কী বা অন্য হিসাবে কী হিসাবে ব্যবহৃত হবে তা গুরুত্বপূর্ণ HashSet<T>since যেহেতু এটি IEqualityComparer<T>আইটেমটি বালতিতে গ্রুপ করার জন্য (কাস্টমটির অভাবে ) ব্যবহৃত হয়। যদি দুটি আইটেমের জন্য হ্যাশ কোডটি মেলে না, সেগুলি কখনই সমান হিসাবে বিবেচিত হবে না ( সমান হিসাবে কখনও কখনও বলা হবে না)।

GetHashCode () পদ্ধতি প্রতিফলিত হওয়া উচিত Equalsযুক্তিবিজ্ঞান; বিধিগুলি হ'ল:

  • যদি দুটি জিনিস সমান হয় ( Equals(...) == true) তবে তাদের অবশ্যই একই মান প্রদান করতে হবেGetHashCode()
  • যদি GetHashCode()সমান হয় তবে তাদের পক্ষে একই হওয়া প্রয়োজন নয় ; এটি একটি সংঘর্ষ, এবং Equalsএটি সত্যিকারের সাম্যতা কিনা তা দেখার জন্য ডাকা হবে।

এই ক্ষেত্রে, দেখে মনে হচ্ছে এটি " return FooId;" একটি উপযুক্ত GetHashCode()বাস্তবায়ন। আপনি যদি একাধিক বৈশিষ্ট্য পরীক্ষা করে দেখেন তবে নীচের মতো কোড ব্যবহার করে এগুলি একত্রিত করা সাধারণ, সাধারণ বা সংঘর্ষগুলি হ্রাস করতে (উদাহরণস্বরূপ যাতে এর new Foo(3,5)আলাদা হ্যাশ-কোড রয়েছে new Foo(5,3)):

unchecked // only needed if you're compiling with arithmetic checks enabled
{ // (the default compiler behaviour is *disabled*, so most folks won't need this)
    int hash = 13;
    hash = (hash * 7) + field1.GetHashCode();
    hash = (hash * 7) + field2.GetHashCode();
    ...
    return hash;
}

ওহ - সুবিধার জন্য, আপনি ওভাররাইডিং এবং যখন অপারেটরগুলি সরবরাহ ==এবং সরবরাহকারী বিবেচনা করতে পারেন ।!=EqualsGetHashCode


আপনি যখন এই ভুলটি পেয়ে যান তখন কী হয় তা একটি প্রদর্শন এখানে


49
আমি কি অহিকে জিজ্ঞাসা করতে পারি আপনি কি এই জাতীয় কারণগুলির সাথে গুণ করছেন?
লেয়ান্দ্রো লোপেজ

22
আসলে, আমি সম্ভবত তাদের একটি হারাতে পারে; পয়েন্টটি সংঘর্ষের সংখ্যা হ্রাস করার চেষ্টা করা উচিত - যাতে কোনও বস্তুর {1,0,0} এর একটি আলাদা হ্যাশ থাকে {0,1,0} এবং {0,0,1 to (আপনি যদি দেখেন তবে আমি কী বোঝাতে চাইছি) ),
মার্ক Gravell

13
আমি এটি পরিষ্কার করার জন্য নম্বরগুলি ট্যুইক করেছি (এবং একটি বীজ যুক্ত করেছেন)। কিছু কোড বিভিন্ন সংখ্যা ব্যবহার করে - উদাহরণস্বরূপ সি # সংকলক (বেনামে ধরণের জন্য) 0x51ed270b এর বীজ এবং -1521134295 এর একটি ফ্যাক্টর ব্যবহার করে।
মার্ক Gravell

76
@ লিয়েনড্রো ল্যাপেজ: সাধারণত সংখ্যার সংঘর্ষের সংখ্যা কম হওয়ার কারণে কারণগুলি প্রাথমিক সংখ্যা হিসাবে বেছে নেওয়া হয়।
আন্দ্রে রিনিয়া

29
"ওহ - সুবিধার জন্য, এছাড়াও আপনি প্রদান পারে বিবেচনা == এবং = অপারেটার যখন সমান এবং GethashCode অগ্রাহ্য।": যে বস্তু অপরিবর্তনীয় নয় তাদের জন্য == অপারেটর বাস্তবায়ন মাইক্রোসফট নিরুৎসাহিত - msdn.microsoft.com/en-us/library/ ms173147.aspx - "অপরিবর্তনীয় ধরণের ক্ষেত্রে অপারেটর == ওভাররাইড করা ভাল ধারণা নয়" "
এন্টিডহ

136

এটি GetHashCode()সঠিকভাবে প্রয়োগ করা খুব শক্ত কারণ কারণ মার্ক ইতিমধ্যে উল্লিখিত বিধিগুলি ছাড়াও হ্যাশ কোডটি কোনও বস্তুর জীবদ্দশায় পরিবর্তন করা উচিত নয়। অতএব হ্যাশ কোড গণনা করতে যে ক্ষেত্রগুলি ব্যবহৃত হয় সেগুলি অবশ্যই অপরিবর্তনীয়।

আমি যখন এনএইচবারনেটের সাথে কাজ করছিলাম তখন অবশেষে এই সমস্যার সমাধান খুঁজে পেয়েছি। আমার পদ্ধতির অবজেক্টের আইডি থেকে হ্যাশ কোড গণনা করা। আইডি কেবল কনস্ট্রাক্টর হিসাবে সেট করা যেতে পারে তাই আপনি যদি আইডিটি পরিবর্তন করতে চান তবে এটি খুব কমই সম্ভাব্য নয়, আপনাকে একটি নতুন অবজেক্ট তৈরি করতে হবে যা একটি নতুন আইডি আছে এবং তাই একটি নতুন হ্যাশ কোড রয়েছে। এই পদ্ধতিটি জিইউইডিগুলির সাথে সর্বোত্তম কাজ করে কারণ আপনি একটি প্যারামিটারলেস কনস্ট্রাক্টর সরবরাহ করতে পারেন যা এলোমেলোভাবে একটি আইডি উত্পন্ন করে।


20
@vanja। আমি বিশ্বাস করি এটির সাথে এটি করার আছে: আপনি যদি কোনও অভিধানে অবজেক্টটি যুক্ত করেন এবং তারপরে অবজেক্টের আইডি পরিবর্তন করেন, পরে আনার সময় আপনি এটি পুনরুদ্ধার করতে একটি ভিন্ন হ্যাশ ব্যবহার করবেন যাতে আপনি অভিধান থেকে কখনই পাবেন না।
এভিনিস

74
মাইক্রোসফ্টের গেটহ্যাশকোড () ফাংশনটির ডকুমেন্টেশনগুলি না বলে দেয় বা বোঝায় না যে অবজেক্ট হ্যাশটিকে অবশ্যই তার জীবদ্দশায় সামঞ্জস্য রাখতে হবে। বস্তুত, এটা বিশেষভাবে এক অনুমোদনযোগ্য ক্ষেত্রে যা এটা হতে পারে ব্যাখ্যা না "একটি বস্তু ধারাবাহিকভাবে দীর্ঘ হিসাবে একই হ্যাশ কোড ফিরে আসবে সেখানে বস্তুর রাষ্ট্র যে বস্তুর এর ফেরত মান পদ্ধতি সমান নির্ধারণ করার কোন পরিমার্জন জন্য GetHashCode পদ্ধতি: । "
পিটারঅ্যালেন ওয়েব

37
"কোনও বস্তুর জীবদ্দশায় হ্যাশ কোডটি পরিবর্তন করা উচিত নয়" - এটি সত্য নয়।
সর্বনাশ

7
এটি বলার আরও ভাল উপায় হ'ল "হ্যাশ কোডটি (সমান উদ্বোধন নয়) সময়কালে অবজেক্টটিকে মূল সংগ্রহ হিসাবে কী হিসাবে ব্যবহার করা হয়" পরিবর্তিত হওয়া উচিত "সুতরাং আপনি যদি কোনও অভিধানে কোনও শব্দকে কী হিসাবে যুক্ত করেন তবে আপনাকে অবশ্যই তা নিশ্চিত করতে হবে আপনি অভিধান থেকে অবজেক্টটি সরিয়ে না দেওয়া পর্যন্ত গেটহ্যাশকোড এবং ইকুয়ালগুলি প্রদত্ত ইনপুটটির জন্য তাদের আউটপুট পরিবর্তন করবে না।
স্কট চেম্বারলাইন

11
@ স্কটচ্যাম্বারলাইন আমি মনে করি আপনি আপনার মন্তব্যে ভুলে গেছেন না, এটি হওয়া উচিত: "হ্যাশ কোডটি (সমান উদ্বোধন) সময়কালে পরিবর্তিত হওয়া উচিত নয় যখন অবজেক্টটি সংগ্রহের মূল হিসাবে ব্যবহৃত হয়"। রাইট?
স্ট্যান প্রকপ

57

ইকুয়ালগুলি ওভাররাইড করে আপনি মূলত বলে রাখছেন যে প্রদত্ত প্রকারের দুটি উদাহরণের তুলনা করতে ভাল জানেন এমন আপনিই, তাই আপনি সম্ভবত সেরা হ্যাশ কোড সরবরাহ করার জন্য সেরা প্রার্থী হতে পারেন।

এটি রিশার্পার কীভাবে আপনার জন্য একটি গেটহ্যাশকোড () ফাংশন লিখেছেন তার একটি উদাহরণ:

public override int GetHashCode()
{
    unchecked
    {
        var result = 0;
        result = (result * 397) ^ m_someVar1;
        result = (result * 397) ^ m_someVar2;
        result = (result * 397) ^ m_someVar3;
        result = (result * 397) ^ m_someVar4;
        return result;
    }
}

আপনি দেখতে পাচ্ছেন যে এটি ক্লাসের সমস্ত ক্ষেত্রের উপর ভিত্তি করে একটি ভাল হ্যাশ কোড অনুমান করার চেষ্টা করে, তবে যেহেতু আপনি নিজের অবজেক্টের ডোমেন বা মান সীমা জানেন তাই আপনি আরও ভাল একটি সরবরাহ করতে পারেন।


7
এটি কি সর্বদা শূন্য ফিরে আসবে না? সম্ভবত ফলাফল 1 টি শুরু করা উচিত! এছাড়াও আরও কয়েকটি আধা-কলোন প্রয়োজন।
স্যাম ম্যাক্রিল

16
এক্সওআর অপারেটর (^) কী করে আপনি জানেন?
স্টিফেন ড্রু

1
যেমনটি আমি বলেছি, আর # আপনার পক্ষে এটি লিখেছেন (কমপক্ষে এটি ২০০৮ সালে ফিরে এসেছিল) যখন জিজ্ঞাসা করা হয়েছিল। স্পষ্টতই, এই স্নিপেটটি কোনও উপায়ে প্রোগ্রামার দ্বারা টুইট করা উচিত। নিখোঁজ আধা-কলোনগুলির জন্য ... হ্যাঁ, দেখে মনে হচ্ছে আমি ভিজ্যুয়াল স্টুডিওতে একটি অঞ্চল নির্বাচন থেকে কোডটি অনুলিপি করে দিলে আমি সেগুলি রেখে দিয়েছি। আমি ভেবেছিলাম লোকেরা উভয়কেই এটি বের করে দেবে।
ট্র্যাপ করুন

3
@ স্যামম্যাক্রিল আমি নিখোঁজ আধা-কলোনগুলিতে যুক্ত করেছি।
ম্যাথিউ মারডোক

5
@SamMackrill না, এটা সবসময় 0. ফিরবে না 0 ^ a = a, তাই 0 ^ m_someVar1 = m_someVar1। তিনি পাশাপাশি প্রাথমিক মান সেট করতে resultপারেন m_someVar1
মিলি স্মিথ

41

nullওভাররাইড করার সময় দয়া করে আপত্তি প্যারামিটারটি পরীক্ষা করতে ভুলবেন না Equals()। এবং টাইপ তুলনা করুন।

public override bool Equals(object obj)
{
    Foo fooItem = obj as Foo;

    if (fooItem == null)
    {
       return false;
    }

    return fooItem.FooId == this.FooId;
}

এর কারণ: Equalsতুলনার তুলনায় অবশ্যই মিথ্যা প্রত্যাবর্তন করতে হবে nullHttp://msdn.microsoft.com/en-us/library/bsc2ak47.aspx এও দেখুন


6
প্রকারের জন্য এই চেকটি এমন পরিস্থিতিতে ব্যর্থ হবে যেখানে একটি সাবক্লাস সুপারক্লাস সমান পদ্ধতিটিকে তার নিজস্ব তুলনার অংশ হিসাবে বোঝায় (যেমন বেস.একুয়ালস (আপত্তি)) - পরিবর্তে ব্যবহার করা উচিত
মিষ্টিফা

@ সুইটফা: এটি সাবক্লাসের সমান পদ্ধতি কীভাবে প্রয়োগ করা হয় তার উপর নির্ভর করে। এটি বেসকেও কল করতে পারে qu
হুহা

2
না এটি হ'ল : এমএসডিএন.মাইক্রোসফট /en-us/library/system.object.gettype.aspx । এবং তদ্ব্যতীত, কোনও পদ্ধতির প্রয়োগটি যেভাবে বলা হয় তার উপর নির্ভর করে ব্যর্থ বা সফল হওয়া উচিত নয়। যদি অবজেক্টের রানটাইম ধরণের কিছু বেসক্লাসের সাবক্লাস হয় তবে বেসক্লাসের সমান () সমান হওয়া উচিত যদি বাস্তবে বেসক্লাসের সমান () কীভাবে ডাকা objহয় তার সমান হয় thisনা।
বৃহস্পতি

2
মুভিং fooItemশীর্ষে এবং তারপর নাল জন্য এটি চেক করার নাল ক্ষেত্রে বা ভুল টাইপ ভালো পারফর্ম করবেন।
ইলিডানএস

1
@ 40 আলফা ভাল, হ্যাঁ, তাহলে obj as Fooঅবৈধ হবে।
IllidanS4 মনিকাকে

35

কেমন:

public override int GetHashCode()
{
    return string.Format("{0}_{1}_{2}", prop1, prop2, prop3).GetHashCode();
}

ধরে নেওয়া পারফরম্যান্স কোনও সমস্যা নয় :)


1
এরম - তবে আপনি কোনও পূর্বনির্ধারিত পদ্ধতির জন্য একটি স্ট্রিং ফিরিয়ে দিচ্ছেন; _0
জিম টোলান

32
না, সে স্ট্রিং অবজেক্ট থেকে গেটহ্যাশকোড () কল করে, যা কোনও পূর্বাবস্থায় ফিরে আসে।
রিচার্ড ক্লেটন

3
আমি আশা করি এটি যতটা দ্রুত হোক আমি চাই, কেবল মূল্যমানের জন্য বক্সিং জড়িতদের জন্যই নয়, পারফরম্যান্সের জন্যও string.Format। আমি দেখেছি আর একটি ভুতুড়ে new { prop1, prop2, prop3 }.GetHashCode()। এই দুজনের মধ্যে কোনটি ধীর হবে তা মন্তব্য করতে পারেন না। সরঞ্জাম অপব্যবহার করবেন না।
নওফাল

16
এটি { prop1="_X", prop2="Y", prop3="Z" }এবং এর জন্য সত্য ফিরে আসবে { prop1="", prop2="X_Y", prop3="Z_" }। আপনি সম্ভবত এটি চান না।
ভয়েটসোয়েবা

2
হ্যাঁ, আপনি সর্বদা আন্ডারস্কোর প্রতীকটি এমন সাধারণ কিছু দিয়ে প্রতিস্থাপন করতে পারেন (যেমন •, ▲, ►, ◄, ☺, ☻) এবং আশা করি আপনার ব্যবহারকারীরা এই চিহ্নগুলি ব্যবহার করবেন না ... :)
লুডমিল টিঙ্কভ

13

আমাদের দুটি সমস্যা মোকাবেলা করতে হবে।

  1. GetHashCode()যদি কোনও বস্তুর ক্ষেত্র পরিবর্তন করা যায় তবে আপনি কোনও বুদ্ধিমানের সরবরাহ করতে পারবেন না । এছাড়াও প্রায়শই কোনও অবজেক্ট নির্ভর করে এমন কোনও সংগ্রহে ব্যবহৃত হবে না GetHashCode()। সুতরাং বাস্তবায়নের ব্যয় GetHashCode()প্রায়শই এটির পক্ষে উপযুক্ত নয় বা এটি সম্ভবও নয়।

  2. কেউ কল একটি সংগ্রহ আপনার বস্তুর রাখে তাহলে GetHashCode()এবং আপনার overrided আছে Equals()এছাড়াও না করে GetHashCode()একটি সঠিক পথ আচরণ, যে ব্যক্তি সমস্যা নিচে ট্র্যাকিং দিন কাটাতে পারে।

অতএব আমি ডিফল্টরূপে করি।

public class Foo
{
    public int FooId { get; set; }
    public string FooName { get; set; }

    public override bool Equals(object obj)
    {
        Foo fooItem = obj as Foo;

        if (fooItem == null)
        {
           return false;
        }

        return fooItem.FooId == this.FooId;
    }

    public override int GetHashCode()
    {
        // Some comment to explain if there is a real problem with providing GetHashCode() 
        // or if I just don't see a need for it for the given class
        throw new Exception("Sorry I don't know what GetHashCode should do for this class");
    }
}

5
গেটহ্যাশকোড থেকে একটি ব্যতিক্রম নিক্ষেপ করা অবজেক্ট চুক্তির লঙ্ঘন। কোনও GetHashCodeফাংশন সংজ্ঞায়িত করতে কোনও অসুবিধা নেই যে কোনও দুটি বস্তু যা সমান হয় একই হ্যাশ কোডটি দেয়; return 24601;এবং return 8675309;উভয়ই এর বৈধ বাস্তবায়ন হবে GetHashCodeDictionaryআইটেমের সংখ্যা ছোট হলেই পারফরম্যান্স শালীন হবে এবং আইটেমের সংখ্যা বড় হয়ে গেলে খুব খারাপ হবে, তবে এটি যে কোনও ক্ষেত্রে সঠিকভাবে কাজ করবে।
সুপারক্যাট

2
@ সুপের্যাট, যদি বস্তুর সনাক্ত ক্ষেত্রগুলি পরিবর্তন করতে পারে তবে বুদ্ধিমান উপায়ে গেটহ্যাশকোড প্রয়োগ করা সম্ভব নয়, কারণ হ্যাশ কোডটি কখনই পরিবর্তন করতে পারে না। আপনি যা বলছেন তা করার ফলে কাউকে পারফরম্যান্স সমস্যার সন্ধান করতে অনেক দিন ব্যয় করতে হতে পারে, তারপরে অভিধানগুলির ব্যবহার অপসারণের জন্য একটি বড় সিস্টেমে পুনরায় নকশার জন্য কয়েক সপ্তাহ weeks
ইয়ান রিংরোজ

2
আমি সমস্ত শ্রেণীর জন্য এই জাতীয় কিছু করতাম আমি সংজ্ঞায়িত করতাম যে সমান প্রয়োজন (), এবং যেখানে আমি পুরোপুরি নিশ্চিত ছিলাম যে আমি কখনই সংগ্রহে কোনও বিষয়টিকে কী হিসাবে ব্যবহার করব না। তারপরে একদিন এমন একটি প্রোগ্রাম যেখানে আমি ডিভ এক্সপ্রেস এক্সট্রাগ্রিড নিয়ন্ত্রণে ক্র্যাশ হয়ে যাওয়া ইনপুট হিসাবে এর মতো একটি বিষয় ব্যবহার করেছি used এটি আমার পিঠের পিছনে এক্সট্রাগ্রিডে পরিণত হয়েছে, হ্যাশ টেবিল বা আমার সামগ্রীর উপর ভিত্তি করে কিছু তৈরি করছে was আমি এই সম্পর্কে ডিএইপপ্রেস সমর্থনকারী লোকদের সাথে একটি সামান্য বিতর্কে জড়িয়ে পড়েছি। আমি বলেছিলাম যে তারা কোনও স্পষ্ট পদ্ধতিতে অজানা গ্রাহক প্রয়োগের উপর তাদের উপাদানগুলির কার্যকারিতা এবং নির্ভরযোগ্যতার ভিত্তিতে স্মার্ট ছিল না।
রেনিপেট

ডিএএক্সপ্রেস লোকেরা বরং ছদ্মবেশী ছিল, মূলত বলেছিল যে গেটহ্যাশকোড () পদ্ধতিতে একটি ব্যতিক্রম ছুঁড়ে ফেলার জন্য আমাকে অবশ্যই বোকা হতে হবে। আমি এখনও তাদের মনে করি যে তারা কী করছে সেগুলি করার একটি বিকল্প পদ্ধতিটি তাদের খুঁজে পাওয়া উচিত - আমি মার্ক গ্রাভেলকে আলাদা থ্রেডের সাথে স্মরণ করি যা বর্ণনা করে যে তিনি কীভাবে গেটহ্যাশকোডের উপর নির্ভরশীল না হয়ে স্বেচ্ছাচারিত বস্তুর একটি অভিধান তৈরি করেন - তিনি কীভাবে এটি করেছিলেন তা স্মরণ করতে পারে না যদিও।
রেনিপেট

4
@ রেনিপিট, অবশ্যই একটি ব্যতিক্রম ছোঁড়ার কারণে ক্রাশ ভাল হওয়া উচিত, তারপরে একটি অবৈধ বাস্তবায়নের কারণে বাগ খুঁজে পাওয়া খুব শক্ত।
আয়ান রিংরোজ

12

এটি কারণ ফ্রেমওয়ার্কটির প্রয়োজন হয় যে দুটি বস্তু একই হয় একই রকম হ্যাশকোড থাকা উচিত। যদি আপনি দুটি বস্তুর একটি বিশেষ তুলনা করতে সমান পদ্ধতিটি ওভাররাইড করেন এবং দুটি বস্তুকে সেই পদ্ধতি দ্বারা একই হিসাবে বিবেচনা করা হয়, তবে দুটি বস্তুর হ্যাশ কোডটিও একই হতে হবে। (অভিধান এবং হ্যাশটেবলগুলি এই নীতির উপর নির্ভর করে)।


11

কেবল উপরের উত্তরগুলি যুক্ত করতে:

আপনি যদি সমানকে ওভাররাইড না করেন তবে ডিফল্ট আচরণটি হ'ল বস্তুর উল্লেখগুলি তুলনা করা হয়। একই হ্যাশকোডে প্রযোজ্য - ডিফল্ট ইমপ্লিমেন্টেশন সাধারণত রেফারেন্সের একটি মেমরি ঠিকানার উপর ভিত্তি করে। যেহেতু আপনি ইক্যুয়েলগুলি ওভাররাইড করেছিলেন এর অর্থ সঠিক আচরণটি হল সমানদের উপর আপনি যা কিছু প্রয়োগ করেছেন তা তুলনা করা এবং রেফারেন্সগুলি নয়, সুতরাং হ্যাশকোডের জন্য আপনার একই কাজ করা উচিত।

আপনার শ্রেণীর ক্লায়েন্টরা হ্যাশকোডের সমান পদ্ধতির অনুরূপ লজিকের প্রত্যাশা করবে, উদাহরণস্বরূপ, লিংক পদ্ধতিগুলি যেগুলি একটি আইক্যুলিটি কম্পিউটার ব্যবহার করে প্রথমে হ্যাশকোডগুলি তুলনা করে এবং কেবল যদি তারা সমান হয় তবে তারা সমান () পদ্ধতির তুলনা করবে যা আরও ব্যয়বহুল হতে পারে চালানোর জন্য, যদি আমরা হ্যাশকোড বাস্তবায়ন না করি, সমান বস্তুর সম্ভবত বিভিন্ন হ্যাশকোড থাকবে (কারণ তাদের মেমরির আলাদা ঠিকানা রয়েছে) এবং সমান না হিসাবে ভুলভাবে নির্ধারিত হবে (সমান () এমনকি আঘাত করবে না)।

এছাড়াও, আপনি যদি কোনও অভিধানে এটি ব্যবহার করেন তবে আপনার সমস্যাটি খুঁজে পেতে সক্ষম হবেন না (কারণ এটি একটি হ্যাশকোড দ্বারা সন্নিবেশ করা হয়েছিল এবং যখন আপনি এটি সন্ধান করছেন তখন সম্ভবত ডিফল্ট হ্যাশকোডটি আলাদা হবে এবং আবার সমান () এমনকি ডাকা হবে না, যেমন মার্ক গ্র্যাভেল তার উত্তরে ব্যাখ্যা করেছেন, আপনি অভিধান বা হ্যাশसेट ধারণার লঙ্ঘনও প্রবর্তন করেন যা অভিন্ন কীগুলি মঞ্জুরি দেয় না - আপনি ইতিমধ্যে ঘোষণা করেছিলেন যে যখন আপনি সমানকে ছাড়িয়ে যান তখন সেই জিনিসগুলি মূলত একই হয় তাই আপনি ডোন না তারা উভয়ই কোনও ডেটা স্ট্রাকচারের আলাদা কী হিসাবে ধরতে চায় না যা মনে করে যে একটি অনন্য কী আছে But তবে তাদের আলাদা হ্যাশকোড থাকায় "একই" কীটি আলাদা আলাদা হিসাবে সন্নিবেশ করা হবে।


8

হ্যাশ কোড হ্যাশ-ভিত্তিক সংগ্রহ যেমন ডিকশনারি, হ্যাশটবেল, হ্যাশসেট ইত্যাদির জন্য ব্যবহৃত হয় এই কোডটির উদ্দেশ্য খুব তাড়াতাড়ি নির্দিষ্ট গোষ্ঠীতে (বালতি) রেখে নির্দিষ্ট বস্তুর প্রাক-বাছাই করা। এই প্রাক-বাছাই করা যখন আপনাকে হ্যাশ-সংগ্রহ থেকে এটি পুনরুদ্ধার করতে হবে তখন এই অবজেক্টটি সন্ধান করতে মারাত্মকভাবে সহায়তা করে কারণ কোডটি আপনার সমস্ত বস্তুর পরিবর্তে কেবলমাত্র একটি বালতিতে আপনার অবজেক্টটি অনুসন্ধান করতে হবে। হ্যাশ কোডগুলির আরও ভাল বিতরণ (আরও ভাল স্বতন্ত্রতা) দ্রুত পুনরুদ্ধার। আদর্শ পরিস্থিতিতে যেখানে প্রতিটি বস্তুর একটি অনন্য হ্যাশ কোড রয়েছে, এটি সন্ধান করা একটি হে (1) ক্রিয়াকলাপ। বেশিরভাগ ক্ষেত্রে এটি ও (1) এর কাছে যায়।


7

এটি অগত্যা গুরুত্বপূর্ণ নয়; এটি আপনার সংগ্রহগুলির আকার এবং আপনার পারফরম্যান্স প্রয়োজনীয়তার উপর নির্ভর করে এবং আপনার ক্লাসটি এমন কোনও লাইব্রেরিতে ব্যবহার করা হবে যেখানে আপনি পারফরম্যান্সের প্রয়োজনীয়তাগুলি জানেন না। আমি প্রায়শই জানি আমার সংগ্রহের আকারগুলি খুব বেশি বড় নয় এবং একটি সঠিক হ্যাশ কোড তৈরি করে আমার কয়েকটি মাইক্রোসেকেন্ডের পারফরম্যান্সের চেয়ে মূল্যবান; সুতরাং (সংকলক দ্বারা বিরক্তিকর সতর্কতা পরিত্রাণ পেতে) আমি সহজভাবে ব্যবহার:

   public override int GetHashCode()
   {
      return base.GetHashCode();
   }

(অবশ্যই আমি সতর্কতাটি বন্ধ করতে একটি # প্রচারণা ব্যবহার করতে পারি তবে আমি এইভাবে পছন্দ করি))

আপনি যে আপনি যখন অবস্থানে আছে কি বিষয় অন্যদের দ্বারা উল্লিখিত সব চেয়ে কর্মক্ষমতা প্রয়োজন এখানে অবশ্যই প্রযোজ্য। সর্বাধিক গুরুত্বপূর্ণ - অন্যথায় আপনি হ্যাশ সেট বা অভিধান থেকে আইটেমগুলি পুনরুদ্ধার করার সময় ভুল ফলাফল পেয়ে যাবেন: হ্যাশ কোডটি কোনও সামগ্রীর আয়ু সময়ের সাথে পৃথক হওয়া উচিত নয় (আরও সঠিকভাবে, যখনই হ্যাশ কোডের প্রয়োজন হয়, যেমন চলাকালীন অভিধানে একটি কী): উদাহরণস্বরূপ, নিম্নলিখিতটি ভ্যালু হিসাবে প্রকাশিত হওয়ায় এটি ভুল এবং উদাহরণের জীবনকালীন সময়ে শ্রেণিতে বাহ্যিকভাবে পরিবর্তিত হতে পারে, সুতরাং আপনাকে অবশ্যই এটি হ্যাশ কোডের ভিত্তি হিসাবে ব্যবহার করবেন না:


   class A
   {
      public int Value;

      public override int GetHashCode()
      {
         return Value.GetHashCode(); //WRONG! Value is not constant during the instance's life time
      }
   }    

অন্যদিকে, যদি মান পরিবর্তন করা যায় না তবে এটি ব্যবহার করা ঠিক হবে:


   class A
   {
      public readonly int Value;

      public override int GetHashCode()
      {
         return Value.GetHashCode(); //OK  Value is read-only and can't be changed during the instance's life time
      }
   }

3
Downvoted। এটি সাধারণ ভুল। এমনকি মাইক্রোসফ্ট এমএসডিএন (এমএসডিএন.মাইক্রোসফটকম /en-us/library/system.object.gethashcode.aspx ) তে বলেছে যে গেটহ্যাশকোডের মান অবশ্যই পরিবর্তিত হবে যখন কোনও বস্তুর রাজ্য এমনভাবে পরিবর্তিত হয় যা কোনও কলের ফেরতের মানকে প্রভাবিত করতে পারে সমান () এবং এটির উদাহরণগুলিতে এটি গেটহ্যাশকোড বাস্তবায়নও দেখায় যা জনসাধারণের পরিবর্তনযোগ্য মানগুলির উপর সম্পূর্ণভাবে নির্ভর করে।
সেবাস্তিয়ান পিআর জিঙ্গার

সেবাস্তিয়ান, আমি একমত নই: আপনি যদি হ্যাশ কোড ব্যবহার করে এমন কোনও সংকলনে কোনও বস্তু যুক্ত করেন তবে এটি হ্যাশ কোডের উপর নির্ভরশীল একটি বিনে স্থাপন করা হবে। আপনি যদি এখন হ্যাশ কোড পরিবর্তন করেন তবে আপনি সংগ্রহটিতে আবার জিনিসটি খুঁজে পাবেন না কারণ ভুল বিনটি অনুসন্ধান করা হবে। এটি আসলে আমাদের কোডে কিছু ঘটেছিল এবং সে কারণেই আমি এটি উল্লেখ করার প্রয়োজনীয়তা পেয়েছি।
ILoveFortran

2
সেবাস্টিয়ান, উপরন্তু, আমি একটি বিবৃতি লিঙ্ক (দেখতে পাবেন msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx ) যে GetHashCode () পরিবর্তন করতে হবে। বিপরীতে - এটি ততক্ষণ পরিবর্তন করতে হবে না যতক্ষণ না সমান একই আর্গুমেন্টের জন্য একই মান দেয়: "কোনও বস্তুর জন্য গেটহ্যাশকোড পদ্ধতিটি ধারাবাহিকভাবে একই হ্যাশ কোডটি ফিরিয়ে আনতে হবে যতক্ষণ না প্রত্যাবর্তন মান নির্ধারণ করে এমন অবজেক্টের স্থিতিতে কোনও পরিবর্তন নেই as অবজেক্টের সমান পদ্ধতির "" এই বিবৃতিটি বিপরীতভাবে বোঝায় না যে সমানদের জন্য ফেরতের মান পরিবর্তন হলে এটি অবশ্যই পরিবর্তন করতে হবে।
ILoveFortran

2
@ জোয়াও, আপনি প্রযোজক / প্রয়োগকারীর সাথে চুক্তির ক্লায়েন্ট / গ্রাহক পক্ষকে বিভ্রান্ত করছেন। আমি প্রয়োগকারীটির দায়িত্ব সম্পর্কে কথা বলছি, যিনি গেটহ্যাশকোড () কে ওভাররাইড করে। আপনি সেই ভোক্তার কথা বলছেন, যিনি মানটি ব্যবহার করছেন।
ILoveFortran

1
সম্পূর্ণ ভুল বোঝাবুঝি ... :) সত্য হ্যাশ কোডটি পরিবর্তন করতে হবে যখন অবজেক্টের অবস্থা পরিবর্তিত হয় যদি না রাষ্ট্রটি বস্তুর পরিচয়ের সাথে অপ্রাসঙ্গিক না হয়। এছাড়াও, আপনার সংগ্রহগুলিতে কী হিসাবে কখনও কখনও একটি অপ্রচলিত বস্তু ব্যবহার করা উচিত নয়। এই উদ্দেশ্যে কেবল পঠনযোগ্য অবজেক্ট ব্যবহার করুন। গেটহ্যাশকোড, সমান ... এবং অন্যান্য কিছু পদ্ধতির নাম যাদের এই মুহুর্তে আমি মনে করি না তাদের উচিত হবে না।
darlove

0

আপনার সর্বদা গ্যারান্টি দেওয়া উচিত যে সমান () দ্বারা সংজ্ঞায়িত হিসাবে যদি দুটি বস্তু সমান হয় তবে তাদের একই হ্যাশ কোডটি ফেরত দেওয়া উচিত। অন্যান্য মতামতগুলির কিছু হিসাবে বলা হয়েছে যে তাত্ত্বিকভাবে এটি বাধ্যতামূলক নয় যদি কোনও জিনিস হ্যাশসেট বা অভিধানের মতো হ্যাশ ভিত্তিক ধারক ক্ষেত্রে ব্যবহার করা না যায়। আমি আপনাকে সর্বদা এই নিয়মটি অনুসরণ করার পরামর্শ দিচ্ছি। কারণটি কেবল কারণ, কারও পক্ষে কার্য সম্পাদনকে উন্নত করার জন্য বা কেবল কোড শব্দার্থককে আরও ভাল উপায়ে পৌঁছানোর ভাল অভিপ্রায় সহ একরকম থেকে অন্য ধরণের সংগ্রহ পরিবর্তন করা সহজ।

উদাহরণস্বরূপ, ধরুন আমরা কিছু বস্তুকে একটি তালিকায় রাখি। কিছুক্ষণ পরে কেউ বুঝতে পেরেছিল যে উদাহরণস্বরূপ আরও ভাল অনুসন্ধান বৈশিষ্ট্যের কারণে একটি হ্যাশসেট অনেক বেশি ভাল বিকল্প। আমরা যখন সমস্যায় পড়তে পারি তখনই এটি হয়। তালিকা অভ্যন্তরীণভাবে সেই ধরণের জন্য ডিফল্ট সমতা তুলনামূলক ব্যবহার করবে যার অর্থ আপনার ক্ষেত্রে সমান এবং হ্যাশশেট গেটহ্যাশকোড () ব্যবহার করে। যদি দুজন আলাদা আচরণ করে তবে আপনার প্রোগ্রামটিও তাই হবে। এবং মনে রাখবেন যে এ জাতীয় সমস্যা সমাধানের পক্ষে সহজতম নয়।

আমি এই আচরণটি একটি ব্লগ পোস্টে আরও কিছু গেটহ্যাশকোড () সমস্যাগুলির সাথে সংক্ষিপ্তসার করেছি যেখানে আপনি আরও উদাহরণ এবং ব্যাখ্যা পেতে পারেন।


0

এর হিসাবে .NET 4.7অগ্রাহ্য এর পছন্দের পদ্ধতি GetHashCode()নিম্নে দেখানো হল। যদি পুরানো .NET সংস্করণগুলিকে লক্ষ্য করে করা হয়, তবে System.ValueTuple nuget প্যাকেজটি অন্তর্ভুক্ত করুন ।

// C# 7.0+
public override int GetHashCode() => (FooId, FooName).GetHashCode();

পারফরম্যান্সের ক্ষেত্রে, এই পদ্ধতিটি বেশিরভাগ সম্মিলিত হ্যাশ কোড বাস্তবায়নকে ছাড়িয়ে যাবে । ValueTuple একটি হল structতাই কোন আবর্জনা হতে হবে না, এবং অন্তর্নিহিত আলগোরিদিম যত দ্রুত এটি পায় হয়।


-1

এটি আমার বোধগম্য যে আসল গেটহ্যাশকোড () বস্তুর মেমরি ঠিকানাটি ফেরত দেয়, সুতরাং আপনি যদি দুটি ভিন্ন বস্তুর তুলনা করতে চান তবে এটি ওভাররাইড করা জরুরী।

সম্পাদনা: এটি ভুল ছিল, আসল গেটহ্যাশকোড () পদ্ধতিটি 2 টি মানের সমতার নিশ্চয়তা দিতে পারে না। যদিও সমান বস্তুগুলি একই হ্যাশ কোডটি দেয়।


-6

প্রতিবিম্বটি ব্যবহার করার নীচে আমার কাছে জনসাধারণের সম্পত্তিগুলি বিবেচনা করার জন্য একটি ভাল বিকল্প বলে মনে হয় কারণ এর সাথে আপনাকে সম্পত্তিগুলি সংযোজন / অপসারণের বিষয়ে চিন্তা করতে হবে না (যদিও এটি এত সাধারণ পরিস্থিতি নয়)। এটি আমি আরও ভাল পারফর্ম করে যাচ্ছিলাম ((ডায়াগনস্টিক্স স্টপ ওয়াচটি ব্যবহারের সাথে তুলনা করে)

    public int getHashCode()
    {
        PropertyInfo[] theProperties = this.GetType().GetProperties();
        int hash = 31;
        foreach (PropertyInfo info in theProperties)
        {
            if (info != null)
            {
                var value = info.GetValue(this,null);
                if(value != null)
                unchecked
                {
                    hash = 29 * hash ^ value.GetHashCode();
                }
            }
        }
        return hash;  
    }

12
গেটহ্যাশকোড () বাস্তবায়ন খুব হালকা ওজনের বলে আশা করা যায়। আমি নিশ্চিত নই যে হাজার হাজার কলগুলিতে স্টপওয়াচের সাথে প্রতিচ্ছবিটি লক্ষণীয়, তবে এটি অবশ্যই লক্ষ লক্ষ লোকের (তালিকার বাইরে একটি অভিধানকে জনপ্রিয় করার কথা ভাবুন) on
বোহদান_ট্রোটসেনকো
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.