প্রোগ্রামিং অনুশীলনীটি C#-এ সমতার বেশ কিছু বৈশিষ্ট্য তুলে ধরে:
Object.Equals()== এবং != দিয়ে সমতার জন্য পরীক্ষা করা হয়। এই টাইপগুলোর সাথেও পাওয়া যায় এমন Equals() মেথড ব্যবহার করার চেয়ে এটাই বেশি প্রচলিত ধরা হয়। তবে Java প্রোগ্রামারদের স্ট্রিং নিয়ে কাজ করার সময় এই বিষয়টি মনে রাখা উচিত যে C#-এ == মান দিয়ে তুলনা করে, কিন্তু তাদের পুরোনো ভাষা Java-তে তা রেফারেন্স দিয়ে তুলনা করে।object থেকে উত্তরাধিকারসূত্রে পাওয়া Equals() মেথড দিয়ে তুলনা করা হয়। যদি সমতা পরীক্ষার উদ্দেশ্য হয় নিশ্চিত করা যে দুটি অবজেক্ট একেবারে একই ইন্সট্যান্স, তাহলে object-এর ইমপ্লিমেন্টেশনের উপর ভরসা করাই যথেষ্ট। তা না হলে object.Equals() ওভাররাইড করতে হবে।Equals() ওভাররাইড করা আবশ্যক।Equals()-এ সাধারণ টাইপের মেম্বারগুলোর জন্য == দিয়ে আর রেফারেন্স টাইপের মেম্বারগুলোর জন্য Equals()-এর রিকার্সিভ কল দিয়ে সমতা পরীক্ষা থাকবে।class StatusBar
{
private readonly int width = 200, height = 20;
public override bool Equals(object other)
{
// ... null and type checks and performance optimisations
return width == (other as StatusBar).width && height == (other as StatusBar).height;
}
}
class Window
{
private readonly string title = "Main";
private readonly StatusBar statusBar = new StatusBar();
public override bool Equals(object other)
{
// ... null and type checks and performance optimisations
return title == (other as Window).title && statusBar.Equals((other as Window).statusBar);
}
}
object.ReferenceEquals() দুটি অবজেক্ট তুলনা করে দেখতে ব্যবহৃত হয় যে তারা এক ও অভিন্ন ইন্সট্যান্স কি না। এটি স্পষ্টতা আনে এবং যেখানে Equals() ও == ওভাররাইড/ওভারলোড করা হয়েছে সেখানে এটি অপরিহার্য।var winA = new Window(); // above code shows that all windows are equal
var winB = new Window();
ReferenceEquals(winA, winB);
// => false
var winC = winA;
ReferenceEquals(winA, winC);
// => true
public override bool Equals(object obj) ছাড়াও IDE-গুলো সাধারণত protected bool Equals(FacialFeatures other) ওভারলোডটি তৈরি করে, যা উত্তরাধিকার জড়িত থাকলে ব্যবহারের জন্য। একটি ডেরাইভড ক্লাস বেস ক্লাসের Equals() কল করে তারপর নিজের পরীক্ষা যোগ করতে পারে।== ব্যবহার করবেন না, যদি না আপনি আপনার ক্লাসে Equals() মেথডের সাথে সাথে == অপারেটরও ওভারলোড করে থাকেন (operator-overloading অনুশীলনীটি দেখুন), অথবা আপনার কাছে শুধু রেফারেন্সগুলো সমান হলেই চলে।structs-এর সমতা পরীক্ষা নিয়ে আলোচনা করা হয়েছে structs অনুশীলনীতে।tuples-এর সমতা নিয়ে আলোচনা করা হয়েছে tuples অনুশীলনীতে।protected bool Equals(T other)
{
return field1 == other.field1 && field2.Equals(other.field2);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((T) obj);
}
SequenceEquals() সরবরাহ করে, কিন্তু LINQ না থাকলে দুটি কালেকশনের ভেতর দিয়ে ইটারেশন করে একেকটি আইটেম আলাদা আলাদাভাবে তুলনা করা ছাড়া উপায় নেই।== ও != কীভাবে ব্যবহার করবেন, তা নিয়ে আলোচনার জন্য operator-overloading অনুশীলনীটি দেখুন।Object.GetHashCode()object.GetHashCode() একটি ৩২ বিটের ইন্টিজারের রূপে হ্যাশ কোড রিটার্ন করে। Dictionary<T> ও HashSet<T>-এর মতো ডিকশনারি ও সেট ক্লাস হ্যাশ কোড ব্যবহার করে অবজেক্ট দ্রুতগতিতে সংরক্ষণ ও পুনরুদ্ধার করে। ডিকশনারির ক্ষেত্রে হ্যাশিং কী (key)-এর সাথে সম্পর্কিত।Equals() ওভাররাইড করেন, তাহলে GetHashCode()-ও ওভাররাইড করবেন। Equals() ও GetHashCode()-এর মধ্যে এমন একটি সম্পর্ক আছে যা ডিকশনারি ও হ্যাশ সেট ক্লাস এবং হ্যাশ কোড ব্যবহার করে এমন অন্য সব ক্লাসের সঠিক আচরণের জন্য সত্য হতে হবে। আপনার কাছ থেকে প্রত্যাশা করা হয় যে আপনি মেথডটি এমনভাবে ইমপ্লিমেন্ট করবেন যাতে ভবিষ্যতে হ্যাশ কোড-ভিত্তিক কোনো কালেকশন যোগ করা মেইনটেইনারদের জন্য কোনো ফাঁদ তৈরি না হয়।Equal() ট্রু রিটার্ন করে) তাহলে ওই দুটি অবজেক্টের GetHashCode() অবশ্যই একই মান রিটার্ন করবে। এর উল্টো দিকটি এখানে প্রযোজ্য নয়। এটি প্রতিসম নয়। একটি লুকআপ ফাংশন কল্পনা করুন যা প্রথমে হ্যাশ কোডের ভিত্তিতে একটি "বাকেট"-এ যায়, তারপর সমতা পরীক্ষা ব্যবহার করে নির্দিষ্ট আইটেমটি বেছে নেয়।HashCode.Combine() কল করা এবং সমতা পরীক্ষায় ব্যবহৃত মানগুলো (বা তার একটি উপসেট) পাস করা। মনে রাখবেন, Combine()-কে যত বেশি তথ্য দেবেন, হ্যাশ ইমপ্লিমেন্টেশন তত বেশি পারফরম্যান্ট হওয়ার সম্ভাবনা থাকে।public class Assessment
{
private int rating;
private Person boss;
public override int GetHashCode()
{
return HashCode.Combine(rating, boss);
}
}
পারফরম্যান্স সামান্য বাড়াতে, বিশেষত যখন অবজেক্টগুলো কোনো কালেকশনের অন্তর্গত, তখন একটি ওভারলোডেড মেম্বার public bool Equals(T other) যোগ করতে পারেন।
এটি রেফারেন্স টাইপের জন্য কিছুটা টাইপ চেকিং বাঁচাবে এবং ভ্যালু টাইপের জন্য একটি বক্সিং ধাপ বাঁচাবে, কারণ public override bool Equals(object other)-এর আর্গুমেন্ট হিসেবে সেগুলোকে আর একটি অবজেক্টে রূপান্তর (বক্স) করতে হবে না।
আপনি যদি আপনার ক্লাসে IEquatable<T> ইন্টারফেস যোগ করেন, তাহলে এই ওভারলোডটি ইমপ্লিমেন্ট করা আবশ্যক হবে। যদি আপনার কোডে এমন রুটিন না থাকে যা IEquatable<T> টাইপের অবজেক্ট নেয় (আর সম্ভবত ইমপ্লিমেন্টিং ক্লাস নির্বিশেষে সমতা নিয়ে মজার কিছু করে), তাহলে ইন্টারফেসটি অন্তর্ভুক্ত করার সত্যিই আর কোনো বাধ্যতামূলক কারণ নেই।
IEqualityComparer<T>যদি এমন একটি ক্লাস থাকে যা দুটি ভিন্ন উপায়ে অনন্যভাবে চিহ্নিত করা যায়, ধরা যাক একটি Person ক্লাস যার একটি SSID আর একটি অনন্য ইমেইল আছে, তাহলে .NET এমন একটি উপায় দেয় যাতে দুটি ভিন্ন কালেকশন ভিন্ন হ্যাশ-কোড ও সমতা পরীক্ষা ব্যবহার করতে পারে। প্রত্যেকটির নিজস্ব Equals() ও GetHashCode() মেথডসহ IEqualityComparer<T>-এর ভিন্ন ইমপ্লিমেন্টেশন থাকতে পারে। আপনি একটি ডিকশনারি রাখতে পারেন যার কী (key) হলো SSID, আর আরেকটি যার কী (key) হলো ইমেইল।
যেখানে IEqualityComparer<T> ব্যবহৃত হচ্ছে, সেখানে সাধারণত কালেকশন ক্লাসের বাইরে সমস্যা এড়াতে আপনি আপনার আইটেম ক্লাসে Equals() ও GetHashCode() তবুও ওভাররাইড করবেন।
IEqualityComparer<T> ব্যবহার করার সময় একটি বিষয় বিবেচনায় রাখতে হবে যে প্রাইভেট মেথড ইত্যাদি সমতা পরীক্ষার জন্য পাওয়া যাবে না।
যদি কেবল একটি হ্যাশড কালেকশন ব্যবহৃত হয়, তাহলে IEqualityComparer<T> এড়িয়ে সমতা ও হ্যাশ কোড অবজেক্টের ভেতরেই এনক্যাপসুলেট করা ভালো হতে পারে। প্রথমেই এটি আদর্শ নয় যে অবজেক্ট আর হ্যাশড কালেকশনের মধ্যে সম্পর্কের মতো একটি গুরুত্বপূর্ণ নির্ভরতা কম্পাইলার দিয়ে নিশ্চিত করা যায় না, কিন্তু হ্যাশিং ও তুলনার লজিক অন্য জায়গায় থাকলে একজন মেইনটেইনারের জন্য কালেকশনের পরিণতি না ভেবেই ক্লাসের মেম্বার বদলে ফেলা আরও সহজ হয়ে যায়।
অসতর্ক কোডারকে চ্যালেঞ্জ করতে পারে এমন একটি প্রিমিটিভ হলো ফ্লোটিং-পয়েন্ট মানের সমতা পরীক্ষা করা। এটি floating-point-numbers কনসেপ্টের about.md ডকুমেন্টে আলোচনা করা হয়েছে।
এই নিবন্ধটি সমতা ও উত্তরাধিকার নিয়ে যেসব সিদ্ধান্ত নিতে হয় তার কিছু দেখায়। এগুলো আপনাকে ভাবাবে কেবল তখনই, যখন আপনি একটি ক্লাস ও একটি ডেরাইভড ক্লাসের ইন্সট্যান্স নিয়ে কাজ করছেন এবং দুটির মধ্যে সমতা পরীক্ষা করা দরকার।