শুধুমাত্র রানটাইমের সময় পরিচিত টাইপ প্যারামিটারের সাথে জেনেরিক পদ্ধতিতে কলিংকে dynamic
প্রতিবিম্ব এপিআইয়ের পরিবর্তে কোনও প্রকার ব্যবহার করে খুব সহজ করা যায় ।
এই কৌশলটি ব্যবহার করতে টাইপটি প্রকৃত অবজেক্ট ( Type
শ্রেণীর উদাহরণ নয় ) থেকে অবশ্যই জানা উচিত । অন্যথায়, আপনাকে সেই ধরণের একটি অবজেক্ট তৈরি করতে হবে বা স্ট্যান্ডার্ড প্রতিবিম্ব এপিআই সমাধান ব্যবহার করতে হবে । আপনি অ্যাক্টিভেটর.ক্রিয়েটআইনস্ট্যান্স পদ্ধতিটি ব্যবহার করে একটি অবজেক্ট তৈরি করতে পারেন ।
আপনি যদি জেনেরিক পদ্ধতিতে কল করতে চান, "সাধারণ" ব্যবহারের ক্ষেত্রে তার ধরণের অনুমান করা হত, তবে এটি কেবল অজানা টাইপের অবজেক্টে কাস্টিংয়ের জন্য আসে dynamic
। এখানে একটি উদাহরণ:
class Alpha { }
class Beta { }
class Service
{
public void Process<T>(T item)
{
Console.WriteLine("item.GetType(): " + item.GetType()
+ "\ttypeof(T): " + typeof(T));
}
}
class Program
{
static void Main(string[] args)
{
var a = new Alpha();
var b = new Beta();
var service = new Service();
service.Process(a); // Same as "service.Process<Alpha>(a)"
service.Process(b); // Same as "service.Process<Beta>(b)"
var objects = new object[] { a, b };
foreach (var o in objects)
{
service.Process(o); // Same as "service.Process<object>(o)"
}
foreach (var o in objects)
{
dynamic dynObj = o;
service.Process(dynObj); // Or write "service.Process((dynamic)o)"
}
}
}
এবং এই প্রোগ্রামটির ফলাফল এখানে:
item.GetType(): Alpha typeof(T): Alpha
item.GetType(): Beta typeof(T): Beta
item.GetType(): Alpha typeof(T): System.Object
item.GetType(): Beta typeof(T): System.Object
item.GetType(): Alpha typeof(T): Alpha
item.GetType(): Beta typeof(T): Beta
Process
একটি জেনেরিক উদাহরণ পদ্ধতি যা পাস করা আর্গুমেন্টের আসল ধরণ ( GetType()
পদ্ধতিটি ব্যবহার করে ) এবং জেনেরিক প্যারামিটারের ধরণ ( typeof
অপারেটর ব্যবহার করে ) লিখে দেয় ।
dynamic
টাইপ করার জন্য অবজেক্ট আর্গুমেন্টটি ingালাইয়ের মাধ্যমে আমরা রানটাইম পর্যন্ত টাইপ প্যারামিটার সরবরাহ স্থগিত করেছি। Process
পদ্ধতিটি যখন dynamic
আর্গুমেন্টের সাথে ডাকা হয় তখন সংকলক এই যুক্তির ধরণের বিষয়ে চিন্তা করে না। সংকলক কোডটি উত্পন্ন করে যা রানটাইমের সময় প্রকৃত প্রকারের আর্গুমেন্টগুলি (প্রতিবিম্ব ব্যবহার করে) পরীক্ষা করে এবং কল করার জন্য সেরা পদ্ধতিটি চয়ন করে। এখানে এখানে কেবলমাত্র একটি জেনেরিক পদ্ধতি রয়েছে, সুতরাং এটি একটি সঠিক ধরণের পরামিতি সহ আহ্বান করা হয়েছে।
এই উদাহরণে, আউটপুট একই হিসাবে আপনি লিখেছেন:
foreach (var o in objects)
{
MethodInfo method = typeof(Service).GetMethod("Process");
MethodInfo generic = method.MakeGenericMethod(o.GetType());
generic.Invoke(service, new object[] { o });
}
ডায়নামিক টাইপের সংস্করণটি অবশ্যই সংক্ষিপ্ত এবং লেখা সহজ। এই ফাংশনটি একাধিকবার কল করার পারফরম্যান্স সম্পর্কেও আপনার চিন্তা করা উচিত নয়। একই ধরণের আর্গুমেন্ট সহ পরবর্তী কলটি ডিএলআর -তে ক্যাশিং ব্যবস্থার জন্য দ্রুত ধন্যবাদ হওয়া উচিত । অবশ্যই, আপনি কোডটি লিখতে পারেন যা ক্যাশে প্রতিনিধিদের আহ্বান জানিয়েছিল, তবে dynamic
প্রকারটি ব্যবহার করে আপনি এই আচরণটি বিনামূল্যে পান।
আপনি যে জেনেরিক পদ্ধতিতে কল করতে চান তাতে যদি প্যারামাইট্রাইজড ধরণের আর্গুমেন্ট না থাকে (সুতরাং এর ধরণের প্যারামিটারটি অনুমান করা যায় না) তবে আপনি জেনেরিক পদ্ধতির অনুরোধটিকে একটি সহায়ক পদ্ধতিতে মোড়ানো করতে পারেন নীচের উদাহরণের মতো:
class Program
{
static void Main(string[] args)
{
object obj = new Alpha();
Helper((dynamic)obj);
}
public static void Helper<T>(T obj)
{
GenericMethod<T>();
}
public static void GenericMethod<T>()
{
Console.WriteLine("GenericMethod<" + typeof(T) + ">");
}
}
প্রকারের সুরক্ষা বৃদ্ধি করা
dynamic
প্রতিবিম্ব API ব্যবহারের জন্য প্রতিস্থাপন হিসাবে অবজেক্টটি ব্যবহার করার ক্ষেত্রে যা দুর্দান্ত তা হল আপনি কেবল রানটাইম অবধি জানেন না এমন এই নির্দিষ্ট ধরণের সংকলনের সময় পরীক্ষাটি হারাবেন। অন্যান্য যুক্তি এবং পদ্ধতির নামটি যথাযথভাবে সংকলক দ্বারা বিশ্লেষণ করা হয়। আপনি যদি আরও যুক্তি সরিয়ে বা যুক্ত করেন, তাদের ধরন পরিবর্তন করুন বা পদ্ধতিটির নাম পরিবর্তন করুন তবে আপনি একটি সংকলন-সময় ত্রুটি পাবেন। আপনি যদি স্ট্রিং হিসাবে পদ্ধতির নাম Type.GetMethod
এবং অবজেক্টগুলিকে অ্যারে হিসাবে আর্গুমেন্ট সরবরাহ করেন তবে এটি ঘটবে না MethodInfo.Invoke
।
নীচে একটি সহজ উদাহরণ দেওয়া আছে যা বোঝায় যে সংকলনের সময় (মন্তব্য কোড) এবং রানটাইমের সময় কিছু ত্রুটি কীভাবে ধরা যেতে পারে। এটিও দেখায় যে কীভাবে DLR কল করতে হবে তা সমাধান করার চেষ্টা করে।
interface IItem { }
class FooItem : IItem { }
class BarItem : IItem { }
class Alpha { }
class Program
{
static void Main(string[] args)
{
var objects = new object[] { new FooItem(), new BarItem(), new Alpha() };
for (int i = 0; i < objects.Length; i++)
{
ProcessItem((dynamic)objects[i], "test" + i, i);
//ProcesItm((dynamic)objects[i], "test" + i, i);
//compiler error: The name 'ProcesItm' does not
//exist in the current context
//ProcessItem((dynamic)objects[i], "test" + i);
//error: No overload for method 'ProcessItem' takes 2 arguments
}
}
static string ProcessItem<T>(T item, string text, int number)
where T : IItem
{
Console.WriteLine("Generic ProcessItem<{0}>, text {1}, number:{2}",
typeof(T), text, number);
return "OK";
}
static void ProcessItem(BarItem item, string text, int number)
{
Console.WriteLine("ProcessItem with Bar, " + text + ", " + number);
}
}
এখানে আমরা আবার কোনও dynamic
ধরণের আর্গুমেন্ট কাস্ট করে কিছু পদ্ধতি কার্যকর করি । প্রথম আর্গুমেন্টের ধরণের কেবল যাচাইকরণটি রানটাইম স্থগিত করা হয়। আপনি যে পদ্ধতিতে কল করছেন তার নামটি উপস্থিত না থাকলে বা অন্য যুক্তি অবৈধ (আর্গুমেন্টের ভুল সংখ্যা বা ভুল ধরণের) থাকলে আপনি একটি সংকলক ত্রুটি পাবেন।
আপনি যখন dynamic
কোনও পদ্ধতিতে যুক্তিটি পাস করেন তখন এই কলটি ইদানীং সীমাবদ্ধ । পদ্ধতির ওভারলোড রেজোলিউশন রানটাইমে ঘটে এবং সেরা ওভারলোড চয়ন করার চেষ্টা করে। সুতরাং আপনি যদি ProcessItem
কোনও BarItem
ধরণের অবজেক্টের সাথে পদ্ধতিটি আহ্বান করেন তবে আপনি প্রকৃতপক্ষে অ-জেনেরিক পদ্ধতিটি কল করবেন কারণ এটি এই ধরণের জন্য আরও ভাল ম্যাচ। যাইহোক, আপনি যখন Alpha
টাইপের একটি যুক্তি পাস করেন তখন আপনি রানটাইম ত্রুটি পাবেন কারণ এই বিষয়টিকে হ্যান্ডেল করতে পারে এমন কোনও পদ্ধতি নেই (একটি জেনেরিক পদ্ধতির সীমাবদ্ধতা রয়েছে where T : IItem
এবং Alpha
শ্রেণি এই ইন্টারফেসটি প্রয়োগ করে না)। তবে এটাই পুরো কথা। সংকলকটির কাছে এই কলটি বৈধ কিনা সেই তথ্য নেই। প্রোগ্রামার হিসাবে আপনি এটি জানেন এবং আপনার এই কোডটি ত্রুটি ছাড়াই চলে কিনা তা নিশ্চিত হওয়া উচিত।
রিটার্ন টাইপ
আপনি গতিশীল ধরনের একটি প্যারামিটার সহ একটি অ অকার্যকর পদ্ধতি আহ্বান করছি, তখন তার রিটার্ন টাইপ সম্ভবত হবে হতে dynamic
খুব । সুতরাং আপনি যদি এই কোডটিতে পূর্ববর্তী উদাহরণটি পরিবর্তন করতে চান:
var result = ProcessItem((dynamic)testObjects[i], "test" + i, i);
তাহলে ফলাফল অবজেক্টের ধরণ হবে dynamic
। এটি কারণ কারণ সংকলক সর্বদা জানেন না যে কোন পদ্ধতিটি ডাকা হবে। আপনি যদি ফাংশন কলের রিটার্নের ধরণটি জানেন তবে আপনার স্পষ্টভাবে এটিকে প্রয়োজনীয় প্রকারে রূপান্তর করা উচিত যাতে বাকী কোডটি স্থিরভাবে টাইপ করা থাকে:
string result = ProcessItem((dynamic)testObjects[i], "test" + i, i);
টাইপটি মেলে না, আপনি রানটাইম ত্রুটি পাবেন।
প্রকৃতপক্ষে, আপনি যদি আগের উদাহরণটিতে ফলাফলের মানটি পেতে চেষ্টা করেন তবে আপনি দ্বিতীয় লুপের পুনরাবৃত্তিতে একটি রানটাইম ত্রুটি পাবেন। এটি কারণ আপনি একটি শূন্য ফাংশনের রিটার্ন মান সংরক্ষণ করার চেষ্টা করেছিলেন।