আপনি যদি C প্রোগ্রামার হন, তবে ডেলিগেটকে ফাংশন পয়েন্টার হিসেবে ভাবতে পারেন। যাইহোক, C#-তে ডেলিগেট একটি সিম্পল ফাংশন পয়েন্টারের চেয়ে অনেক বেশি। এই আর্টিকেলটি ডেলিগেট কনসেপ্ট এবং দিনদিনের প্রোগ্রামিং-এ এর ব্যবহার ব্যাখ্যা করে।
মূলত, ডেলিগেট একটি ইন্ডিরেকশন লেভেল প্রদান করে। তারা একটি কোডের টুকরো এনক্যাপসুলেট করে যা পাস করা যায় এবং টাইপ-সেফভাবে এক্সিকিউট করা যায়। আচরণটি তৎক্ষণাৎ এক্সিকিউট করার বদলে, এটি একটি অবজেক্টে সংরক্ষিত থাকে। সেই অবজেক্টের ওপর আপনি একাধিক অ্যাকশন পারফর্ম করতে পারেন, এবং 그중 একটি হলো সংরক্ষিত আচরণটি এক্সিকিউট করা।
ডেলিগেট ব্যবহার করে আমরা হাইয়ার-অর্ডার ফাংশন লিখতে পারি, অর্থাৎ ফাংশন যেগুলো ফাংশন প্যারামিটার হিসেবে গ্রহণ করতে পারে বা রিটার্ন ভ্যালু হিসেবে ফাংশন রিটার্ন করতে পারে। একটি ডেলিগেট টাইপ সেই মেথড সিগনেচার ডিফাইন করে যা ডেলিগেট রিপ্রেজেন্ট করতে পারে, cụ thể মেথডের রিটার্ন টাইপ এবং এর প্যারামিটার টাইপগুলো। নিচের উদাহরণে, Transformer হলো একটি ডেলিগেট যা যেকোনো মেথড রিপ্রেজেন্ট করতে পারে যা একটি ইন্টিজার গ্রহণ করে এবং একটি ইন্টিজার রিটার্ন করে।
delegate int Transformer(int x);
আমরা যেকোনো মেথড (ল্যাম্বডা, ইনস্ট্যান্স, বা স্ট্যাটিক মেথডসহ) Transformer-এর একটি ইনস্ট্যান্সে অ্যাসাইন করতে পারি যা সিগনেচার পূরণ করে। উদাহরণস্বরূপ —
Transformer square = x => x * x; Transformer cube = x => x * x * x; Console.WriteLine(square(3)); // prints 9 Console.WriteLine(cube(5)); // prints 125
কবে ডেলিগেট ব্যবহার করবেন?
ডেলিগেট সাধারণত তখন ব্যবহার হয় যখন কোডটি কিছু অ্যাকশন এক্সিকিউট করতে চায় কিন্তু সেই অ্যাকশনগুলো কী হবে তার ডিটেইল জানে না, শুধু সেই অ্যাকশনগুলোর ইন্টারফেস জানে।
প্রোগ্রামিং-এ আমরা প্রায়ই এমন পরিস্থিতি মোকাবিলা করি যেখানে আমাদের একটি নির্দিষ্ট অ্যাকশন এক্সিকিউট করতে হয়, কিন্তু আমরা অগ্রিমে না জানি কোন মেথডকে কল করতে হবে সেটি এক্সিকিউট করার জন্য। ডেলিগেট এই সমস্যাটি সমাধান করে সেই আচরণকে একটি ডেলিগেট দিয়ে রিপ্লেস করে এবং তারপর কনটেক্সট এবং পরিস্থিতির المناسب আচরণযুক্ত ডেলিগেটের একটি কনক্রিট ইনস্ট্যান্স পাস করে।
একটি ডেলিগেট কিছু করার জন্য চারটি জিনিস ঘটতে হবে —
১) ডেলিগেট টাইপ ডিক্লেয়ার করতে হবে।
একটি ডেলিগেট টাইপ মূলত সেই ফাংশনের ডেফিনিশন যা সেটি রিপ্রেজেন্ট করছে, অর্থাৎ এতে ফাংশনটি যে প্যারামিটার টাইপগুলো গ্রহণ করবে এবং যে রিটার্ন টাইপ রিটার্ন করবে সেটি থাকে।
উদাহরণস্বরূপ, একটি ডেলিগেট টাইপ যা দুটি নম্বর ইনপুট নেয় এবং একটি নম্বর রিটার্ন করে, সেটি নিচের মতো ডিক্লেয়ার করা যায় —
delegate int Processor(int numOne, int numTwo);
Processor হলো একটি টাইপ, ক্লাস দ্বারা তৈরি টাইপের মতো। এই টাইপের একটি ইনস্ট্যান্স তৈরি করতে, আপনাকে একটি মেথড প্রয়োজন যা দুটি নম্বর ইনপুট নেয় এবং একটি বুল রিটার্ন করে।
২) এক্সিকিউট হওয়া কোডটি একটি মেথডে থাকতে হবে।
একটি মেথড ডিফাইন করুন যা উপরের ডেলিগেট টাইপের সাথেই সেম সিগনেচার রাখে এবং রানটাইমে পরিস্থিতির মোতাবেক সেটি করে। উদাহরণস্বরূপ, নিচের যেকোনো মেথড Processor-এর একটি ইনস্ট্যান্স তৈরি করতে ব্যবহার করা যায়, কারণ সেগুলো সবই দুটি নম্বর নেয় এবং একটি নম্বর রিটার্ন করে।
static int Add(int numOne, int numTwo){ Return numOne + numTwo; } static int Subtract(int numOne, int numTwo){ Return numOne - numTwo; }৩) একটি ডেলিগেট ইনস্ট্যান্স তৈরি করতে হবে।
এখন আপনার কাছে একটি ডেলিগেট টাইপ এবং সঠিক সিগনেচারيلا একটি মেথড আছে, আপনি সেই ডেলিগেট টাইপের একটি ইনস্ট্যান্স তৈরি করতে পারেন। এটি করলে, আমরা মূলত C# কম্পাইলারকে বলছি যে যখন ডেলিগেট ইনস্ট্যান্সটি ইনভোক হবে, তখন এই মেথডটি এক্সিকিউট কর।
Processor processorOne = new Processor(Add); Processor processorTwo = new Processor(Subtract);
উপরের উদাহরণে অনুমান করা হয়েছে যে Add এবং Subtract মেথডগুলো সে ক্লাসে ডিফাইন করা আছে যেখানে আমরা ডেলিগেট ইনস্ট্যান্স তৈরি করছি। যদি মেথডগুলো অন্য ক্লাসে ডিফাইন করা থাকে, তবে আমাদের সে ক্লাসের ইনস্ট্যান্স প্রয়োজন হবে।
৪) ডেলিগেট ইনস্ট্যান্সটি ইনভোক করতে হবে।
এটি শুধু ডেলিগেট ইনস্ট্যান্সে একটি মেথড কল করার বিষয়, যেটির নাম হলো, অবিশ্বাস্যভাবে, Invoke। ডেলিগেট ইনস্ট্যান্সের এই মেথডটির প্যারামিটার লিস্ট এবং রিটার্ন টাইপ সেম থাকে যা ডেলিগেট টাইপ ডিক্লেয়ারেশনে স্পেসিফাই করা আছে। Invoke কল করলে ডেলিগেট ইনস্ট্যান্সের অ্যাকশন এক্সিকিউট হবে।
int sum = processorOne.Invoke(3, 5);
তবে, C# এটাকে আরও সহজ করে দিয়েছে। আপনি সরাসরি ডেলিগেট ইনস্ট্যান্সকে ইনভোক করতে পারেন যেন সেটি নিজে একটি মেথড হয়। উদাহরণস্বরূপ,
int difference = processorTwo(10, 6);
ডেলিগেট কম্বাইন ও রিমুভ করা
যদি আমরা একাধিক ভিন্ন অ্যাকশন একটি ডেলিগেট ইনস্ট্যান্সের একক ইনভোকেশন দিয়ে এক্সিকিউট করতে চাই, C# সেটি করার অনুমতি দেয়। System.Delegate টাইপে দুটি স্ট্যাটিক মেথড রয়েছে, Combine এবং Remove।
১. Combine
একটি নতুন ডেলিগেট তৈরি করে যার ইনভোকেশন লিস্ট প্যারামিটার হিসেবে পাস করা ডেলিগেটগুলোর ইনভোকেশন লিস্ট কনক্যাটেনেট করে তৈরি হয়। নতুন ডেলিগেট ইনস্ট্যান্স ইনভোক করলে তার সব অ্যাকশন ক্রম대로 এক্সিকিউট হয়।
public static Delegate Combine(params Delegate[] delegates); // OR public static Delegate Combine(Delegate a, Delegate b);
যদি ইনভোকেশন লিস্টের যেকোনো অ্যাকশন এক্সেপশন থ্রো করে, তবে তার পরের কোনো অ্যাকশন এক্সিকিউট হয় না।
২. Remove
এক ডেলিগেটের ইনভোকেশন লিস্ট থেকে অন্য ডেলিগেটের ইনভোকেশন লিস্টের শেষ অকারেন্স রিমুভ করে। সোর্সের ইনভোকেশন লিস্ট নেওয়া হয় এবং ভ্যালুর ইনভোকেশন লিস্টের শেষ অকারেন্স বাদ দিয়ে একটি নতুন ডেলিগেট রিটার্ন করে যার ইনভোকেশন লিস্ট তৈরি হয়।
public static Delegate Remove(Delegate source, Delegate value);
সারসংক্ষেপ
ডেলিগেট একটি নির্দিষ্ট টাইপ এবং প্যারামিটার সেটের সাথে আচরণ এনক্যাপসুলেট করে, একটি সিঙ্গল-মেথড ইন্টারফেসের মতো।
একটি ডেলিগেট টাইপ ডিক্লেয়ারেশনে বর্ণিত টাইপ সিগনেচার নির্ধারণ করে কোন মেথডগুলো ডেলিগেট ইনস্ট্যান্স তৈরি করতে ব্যবহার করা যাবে এবং ইনভোকেশনের সিগনেচার।
একটি ডেলিগেট ইনস্ট্যান্স তৈরি করতে একটি মেথড প্রয়োজন যা আমরা ডেলিগেট ইনভোক হওয়ার সময় এক্সিকিউট করতে চাই।
ডেলিগেট ইনস্ট্যান্স ইমিউটেবল, স্ট্রিং-এর মতো।
প্রতিটি ডেলিগেট ইনস্ট্যান্সে একটি ইনভোকেশন লিস্ট থাকে - অ্যাকশনদের একটি লিস্ট।
ডেলিগেট ইনস্ট্যান্স একে অপরের সাথে কম্বাইন ও রিমুভ করা যায়।
উদাহরণ
using System; class Program{ delegate int Transformer(int x); delegate int Processor(int numOne, int numTwo); static void Main(){ Transformer square = x => x * x; Transformer cube = x => x * x * x; Console.WriteLine(square(3)); // prints 9 Console.WriteLine(cube(5)); // prints 125 Processor processorOne = new Processor(Add); Processor processorTwo = new Processor(Subtract); int sum = processorOne.Invoke(3, 5); Console.WriteLine(sum); // prints 8 int difference = processorTwo(10, 6); Console.WriteLine(difference); // prints 4 } static int Add(int numOne, int numTwo){ return numOne + numTwo; } static int Subtract(int numOne, int numTwo){ return numOne - numTwo; } }আউটপুট
9 125 8 4