جواد مهدی‌نیا 830 0 کامنت 1401/2/9

آشنایی با جنریک ها در زبان سی‌شارپ

جنریک‌ها (Generics) و روش استفاده از آنها از جمله قابلیت‌هایی است که به عنوان یک برنامه نویس سی‌شارپ باید با آنها آشنا باشید و از آن استفاده کنید.

جنریک ها در سی شارپ

ارائه یک مثال از جنریک

برای اینکه بتوانیم نشان دهیم که جنریک چیست و چه کاربردی دارد، این مساله را با ارائه یک مثال در یک پروژه کوچک Console Application می‌خواهیم نشان دهیم. پس از ارائه این مثال به با Genericها آشنا خواهید شد و دید مناسبی نسبت به آنها خواهید داشت.

کدهای زیر را که در ویژوال استودیو نوشته شده است را ببینید.

class Program
    {
        static void Main(string[] args)
        {
            Calculator calculator = new Calculator();
            calculator.Compare(12, 15);

            Console.ReadKey();
        }


    }
    class Calculator
    {
        public void Compare(int a , int b)
        {
            bool result = (a == b);
            Console.WriteLine($"Result: {result}");
        }
    }

همانطور که مشاهده می‌شود، ما از یک متد به نام Compare در کلاس Calculator برای نشان دادن نتیجه مقایسه دو عدد استفاده کردیم. این یک متد معمولی است که از آن برای مقایسه استفاده کردیم. حال فرض کنید که به جای مقایسه دو عدد، بخواهیم دو رشته را به متد برای محاسبه دو مقدار بدهیم. مسلما برای اینکه اگر در داخل کلاس program رشته وارد کنیم به خطا بر می‌خوریم و لازم است که نوع داده‌ها را در متد Compare هم تغییر داده و به string تبدیل کنیم. به این شکل:

        public void Compare(string a , string b)
        {
            bool result = (a == b);
            Console.WriteLine($"Result: {result}");
}

حالا می‌توانیم با ارسال رشته‌های مورد نظر به عنوان پارامتر به این متد، مقایسه را انجام داد و نتیجه را نمایش داد.

اما آیا راهی وجود داد که بدون اینکه هربار لازم باشد تا نوع متغیرهای این متد را مجددا تایپ کنیم، این عملیات را انجام دهیم؟ در پاسخ باید گفت بله؛ اما چطور؟ پاسخ به این سوال در این مساله نهفته است که همه انواع داده‌ای یا Data Typeها، در اصل از نوع Object هستند. پس اگر متد را به شکل زیر بنویسیم، همه نوع داده را می‌توانیم بدون خطا به آن ارسال کنیم:

        public void Compare(object  a , object b)
        {
            bool result = (a.Equals(b));
            Console.WriteLine($"Result: {result}");
        }

توجه کنید که برای مقایسه دو object از عملگر == استفاده نمی‌توانیم بکنیم و به همین دلیل از متد Equals استفاده کردیم.

حال که متد ما object دریافت می‌کند، هر نوع داده‌ای را می‌توانیم به آن ارسال کنیم و خروجی مناسب را بگیریم. اما دو مشکل در اینجا وجود دارد. این مشکل، انجام شدن Boxing غیر ضروری  و در نتیجه کاهش عملکرد در تبدیل انواع مقداری به انواع ارجاعی در این مثال ساده است که هدف  ما مقایسه دو مقدار می‌باشد. از طرف دیگر در هنگام فراخوانی تابع، حتی اگر دو مقدار ارسال شده در بالا از یک نوع نباشند (مثلا a از نوع int و b از نوع رشته) هم این مقایسه انجام شده و نتیجه را بر می‌گردد که از type safe بودن و strongly type بودن می‌کاهد.

اما برای حل این مشکلات چه باید کرد؟ در واقع باید کاری کرد؟ یک روش مناسب برای رفع این مشکلات استفاده از جنریک است. به این منظور می‌توانیم با روش زیر، متد را جنریک کرده و از نوع دریافتی آن مستقل کنیم. در واقع با این کار، نوع متغیرها در هنگام پیاده‌سازی متد تعیین می‌شود.

    class Calculator
    {
        public void Compare<T>(T a , T b)
        {
            bool result = (a.Equals(b));
            Console.WriteLine($"Result: {result}");
        }
    }

همانطور که می‌بینید، نوع متغیرها نامشخص است و باید هنگام فراخوانی متد تعیین شود. فراخوانی این متد را در مثال زیر ببینید که چگونه نوع متغیرها را در هنگام فراخوانی متد تعیین کردیم. دقت کنید، هنگامی که <string> یا هر نوع داده را به این صورت مشخص کردیم، دیگر متغیرها نمی‌توانند چیزی غیر از آن باشند. به عنوان مثال فراخوانی متد کلاس بالا را که یک بار از نوع string و بار دوم از نوع int است را ببینید.

    class Program
    {
        static void Main(string[] args)
        {
            Calculator calculator = new Calculator();
            calculator.Compare<string>("AB", "CD");
            calculator.Compare<int>(5, 5);
            Console.ReadKey();
        }
    }

دقت کنید که به جای T می‌توانید هر حرف دیگری قرار دهید؛ اما با این حال استفاده از T که مخفف Type است، با مسماتر است و به این ترتیب قواعد Strongly Type هم رعایت می‌شود.

می‌توانی به جای روش بالا، اگر بخواهیم کل کلاس را جنریک کنیم که به این منظور به شکل زیر عمل می کنیم:

   class Program
    {
        static void Main(string[] args)
        {
            Calculator<int> calculator = new Calculator<int>();
            calculator.Compare(1, 1);


            Console.ReadKey();
        }
    }
    class Calculator<T>
    {
        public void Compare(T a, T b)
        {
            bool result = (a.Equals(b));
            Console.WriteLine($"Result: {result}");
        }
    }

مزایای استفاده از Generic

اگر بخواهیم مزایای استفاده از Generic ها را خلاصه کنیم، باید بگوییم با استفاده از جنریک‌ها، برنامه‌های ما مزایای زیر را کسب می‌کنند:

1- ساده‌تر شدن کدها.

2- کم شدن حجم کدنویسی.

3- ارتقای قابلیت استفاده مجدد از کدها

4- عملکرد بالاتر در اجرا برنامه.

5- امکان type safe بودن.

لینک این مقاله را در شبکه‌های اجتماعی به اشتراک بگذارید.

دیدگاه خود را ثبت کنید

دیدگـاه مخاطبــان
نظری ثبت نشده است، شما اولین نفر باشید!