আমি আপনার এক্সপার্ট সফটওয়্যার ইঞ্জিনিয়ারিং ট্রেইনার। কোর্স আউটলাইন অনুযায়ী, আমরা এখন Section 15: xUnit testing-এর ভেতরে আছি। আগের লেকচারে আমরা সর্টিং ফাংশনালিটি বা GetSortedPersons মেথডটির জন্য Unit Test লিখেছিলাম। এই লেকচারে আমরা মেথডটির আসল লজিক (Implementation) লিখব, যাতে টেস্টগুলো পাস করে।
চলুন, আজকের লেকচারটি গুছিয়ে ও বিস্তারিতভাবে বুঝে নেওয়া যাক।
📝 Lecture Summary (Quick Revision)
ভবিষ্যতে দ্রুত রিভিশন দেওয়ার জন্য সম্পূর্ণ লেকচারের মূল কাজগুলো নিচে লিস্ট আকারে দেওয়া হলো:
- Initial Setup & Validation: ইনপুট
sortByযদিnullবা খালি হয়, তবে মেথডটি কোনো সর্টিং ছাড়াই সরাসরিallPersonsলিস্ট রিটার্ন করবে। - Switch Expression (C# 8+): ট্র্যাডিশনাল
switch-case-এর বদলে আধুনিক Switch Expression ব্যবহার করা হয়েছে, যা কোডকে অনেক বেশি কনসাইস (Concise) বা ছোট করে। - Tuple Matching:
(sortBy, sortOrder)এর ওপর ভিত্তি করে একসাথে দুটি কন্ডিশন চেক করা হয়েছে। - LINQ Sorting:
OrderBy(Ascending এর জন্য) এবংOrderByDescending(Descending এর জন্য) ব্যবহার করা হয়েছে। - Case-Insensitive Sorting: স্ট্রিং টাইপ ডেটা (যেমন:
PersonName,Email) সর্ট করার সময়StringComparer.OrdinalIgnoreCaseব্যবহার করা হয়েছে। - Default Case (
_): যদি ইউজার এমন কোনো কলামের নাম দেয় যা সিস্টেমে নেই, তবে ডিফল্ট হিসেবে মূল লিস্টটিই (allPersons) রিটার্ন করা হবে। - Test Verification: টেস্ট রান করে দেখা যে
GetSortedPersons_ToBeSuccessfulটেস্টটি সফলভাবে পাস করেছে।
🧠 Comprehensive Breakdown
এই লেকচারে আমরা একটি ডায়নামিক সর্টিং মেকানিজম তৈরি করেছি। চলুন প্রতিটি ধাপ বিস্তারিতভাবে বুঝে নিই।
১. Initial Validation (Priority: 8/10)
Concept & Why: যখন ইউজার গ্রিডে বা টেবিলে সর্ট করার জন্য কোনো কলামে ক্লিক করবে না, তখন sortBy প্যারামিটারটি খালি থাকতে পারে। এই অবস্থায় ডেটা সর্ট করার কোনো দরকার নেই। তাই শুরুতেই চেক করে মূল ডেটা রিটার্ন করে দেওয়া হয়েছে।
public List<PersonResponse> GetSortedPersons(List<PersonResponse> allPersons, string sortBy, SortOrderOptions sortOrder)
{
// যদি sortBy ফাঁকা হয়, তবে যা ইনপুট এসেছে তাই আউটপুট হবে
if (string.IsNullOrEmpty(sortBy))
{
return allPersons;
}
// ... পরবর্তী লজিক
}
২. C# Switch Expression & Tuple Matching (Priority: 10/10)
Concept & Why: গত লেকচারে সার্চ করার সময় আমরা ট্র্যাডিশনাল switch ব্যবহার করেছিলাম, যা অনেক জায়গা নিয়েছিল। এবার আমরা C# 8-এর Switch Expression ব্যবহার করেছি।
যেহেতু আমাদের সর্টিং দুটি জিনিসের ওপর নির্ভর করছে— কোন কলাম (sortBy) এবং কোন অর্ডার (sortOrder), তাই আমরা এই দুটিকে একটি Tuple (sortBy, sortOrder) বানিয়ে তারপর switch করেছি।
List<PersonResponse> sortedPersons = (sortBy, sortOrder) switch
{
// Case 1: Name & Ascending
(nameof(PersonResponse.PersonName), SortOrderOptions.Ascending)
=> allPersons.OrderBy(temp => temp.PersonName, StringComparer.OrdinalIgnoreCase).ToList(),
// Case 2: Name & Descending
(nameof(PersonResponse.PersonName), SortOrderOptions.Descending)
=> allPersons.OrderByDescending(temp => temp.PersonName, StringComparer.OrdinalIgnoreCase).ToList(),
// ... অন্যান্য প্রপার্টির জন্য একই লজিক
};
৩. Data Type Specific Logic (Priority: 9/10)
Concept & Why: সর্ট করার লজিক ডেটা টাইপের ওপর নির্ভর করে কিছুটা ভিন্ন হয়।
- String Types (
PersonName,Email,Address): ছোট হাতের “a” এবং বড় হাতের “Z” এর মধ্যে কনফ্লিক্ট এড়ানোর জন্যStringComparer.OrdinalIgnoreCaseব্যবহার করা হয়েছে। - Non-String Types (
DateOfBirth,Age,ReceiveNewsLetters): নাম্বার বা ডেটের ক্ষেত্রে কেস (Case) বলে কিছু নেই। তাই এখানেStringComparerব্যবহার করার দরকার নেই।
// DateOfBirth এর জন্য StringComparer নেই
(nameof(PersonResponse.DateOfBirth), SortOrderOptions.Ascending)
=> allPersons.OrderBy(temp => temp.DateOfBirth).ToList(),
৪. Default Case or Discard Pattern (_) (Priority: 8/10)
Concept & Why: Switch Expression-এ যদি কোনো কন্ডিশন ম্যাচ না করে, তবে C# একটি Exception থ্রো করে। এটি ঠেকানোর জন্য সবশেষে একটি ডিফল্ট কেস লিখতে হয়। Switch Expression-এ ডিফল্ট কেস বোঝাতে আন্ডারস্কোর _ (যাকে Discard প্যাটার্ন বলে) ব্যবহার করা হয়।
// Default Case
_ => allPersons
}; // Switch expression ends here
// শেষে সর্টেড লিস্ট রিটার্ন করা
return sortedPersons;
৫. Unit Test Result (Priority: 6/10)
লজিক লেখা শেষ করে Test Explorer রান করলে দেখা যায়, আগের লেকচারে লেখা GetSortedPersons_ToBeSuccessful টেস্টটি সফলভাবে পাস করেছে। এবং ITestOutputHelper থাকার কারণে আমরা Console/Details উইন্ডোতে Expected এবং Actual ডেটা দেখতে পাচ্ছি, যা ডেটা মেলাতে সাহায্য করে।
🚀 Modern C# (.NET 10 Update) & Smarter Approach
লেকচারের পদ্ধতিটি দারুণ এবং C#-এর মডার্ন ফিচার (Switch Expression) খুব সুন্দরভাবে ব্যবহার করা হয়েছে। তবে লেকচারার ভিডিওর শেষের দিকে বলেছিলেন, “To avoid the repetition you can try using reflection”, কিন্তু কনফিউশন এড়ানোর জন্য তিনি সেটি দেখাননি।
রিয়েল-ওয়ার্ল্ড এন্টারপ্রাইজ প্রোজেক্টে (বিশেষ করে যখন আপনার মডেলে ২০-৩০টি কলাম থাকে), এতগুলো switch কেস ম্যানুয়ালি লেখা মেনটেইনেবল নয়। আমরা তখন Reflection বা LINQ Expression Trees ব্যবহার করে একটি জেনেরিক ডাইনামিক সর্টিং হেল্পার তৈরি করি।
Smarter Dynamic Sorting (Advanced Approach using Reflection):
// System.Reflection ব্যবহার করে ডায়নামিক সর্টিং (কোনো Switch Case ছাড়াই!)
public List<PersonResponse> GetSortedPersons(List<PersonResponse> allPersons, string sortBy, SortOrderOptions sortOrder)
{
if (string.IsNullOrEmpty(sortBy) || !allPersons.Any())
return allPersons;
// ১. প্রপার্টি ইনফরমেশন বের করা
var propertyInfo = typeof(PersonResponse).GetProperty(sortBy, System.Reflection.BindingFlags.IgnoreCase | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
// ২. যদি প্রপার্টি না পাওয়া যায়, তবে অরিজিনাল লিস্ট রিটার্ন করা
if (propertyInfo == null)
return allPersons;
// ৩. ডাইনামিক্যালি সর্ট করা
if (sortOrder == SortOrderOptions.Ascending)
{
return allPersons.OrderBy(x => propertyInfo.GetValue(x, null)).ToList();
}
else
{
return allPersons.OrderByDescending(x => propertyInfo.GetValue(x, null)).ToList();
}
}
কেন এটি স্মার্ট? কারণ কাল যদি আপনি আপনার মডেলে নতুন ৫টি কলাম যোগ করেন, তাহলেও আপনাকে সর্টিং মেথডে এসে নতুন কোনো switch-case লিখতে হবে না!
🏆 Best Practices (For Sorting)
- Use Tuple Patterns: যখন একাধিক ভ্যারিয়েবলের ওপর ভিত্তি করে সিদ্ধান্ত নিতে হয়, তখন নেস্টেড
if-elseলেখার চেয়ে Tuple Switch Expression(a, b) switch { ... }ব্যবহার করাটা বেস্ট প্র্যাকটিস। - StringComparer is Crucial: মেমরিতে (LINQ to Objects) স্ট্রিং সর্ট করার সময় সব সময়
StringComparer.OrdinalIgnoreCaseব্যবহার করবেন, নতুবা আপনার সর্টিং অ্যালফাবেটিক্যাল অর্ডারে না হয়ে অ্যাসকি (ASCII) ভ্যালুর ওপর ভিত্তি করে হবে (যেমন Z এর আগে a চলে আসবে)। - Database Sorting vs Memory Sorting: বর্তমানে আমরা সব ডেটা মেমরিতে (
List) এনে তারপর C# দিয়ে সর্ট করছি। কোর্সের পরবর্তী অংশে যখন Entity Framework আসবে, তখন চেষ্টা করবেন সর্টিংয়ের কাজটি সার্ভারে (ডাটাবেসে)IQueryableএর ওপর করতে, মেমরিতে নয়।