سه شنبه ۲۷ شهريور ۱۴۰۳
Tut24 آموزش برنامه نویسی و مجله تخصصی فناوری ورود/عضویت

آموزش سی شارپ - جنریک‌ها

جنریک‌ها به شما امکان می‌دهند تا مشخصات نوع داده‌ها را در عناصر برنامه‌نویسی در یک کلاس یا یک متد تعریف کنید تا در زمان استفاده واقعی از آن‌ها در برنامه،نوع داده معلوم شود. به عبارت دیگر، جنریک‌ها به شما امکان می‌دهند تا یک کلاس یا متدی بنویسید که با هر نوع داده‌ای کار کند.

شما مشخصات کلاس یا متد را با پارامترهای جایگزین برای انواع داده‌ها می‌نویسید. زمانی که کامپایلر با یک سازنده برای کلاس یا فراخوانی تابع برای متد ، مواجه می‌شود، کدی را تولید می‌کند تا با نوع داده خاص کار کند. یک مثال ساده به درک این مفهوم کمک می‌کند −

using System;
using System.Collections.Generic;

namespace GenericApplication {
   public class MyGenericArray<T> {
      private T[] array;
      
      public MyGenericArray(int size) {
         array = new T[size + 1];
      }
      public T getItem(int index) {
         return array[index];
      }
      public void setItem(int index, T value) {
         array[index] = value;
      }
   }
   class Tester {
      static void Main(string[] args) {
         
         //declaring an int array
         MyGenericArray<int> intArray = new MyGenericArray<int>(5);
         
         //setting values
         for (int c = 0; c < 5; c++) {
            intArray.setItem(c, c*5);
         }
         
         //retrieving the values
         for (int c = 0; c < 5; c++) {
            Console.Write(intArray.getItem(c) + " ");
         }
         
         Console.WriteLine();
         
         //declaring a character array
         MyGenericArray<char> charArray = new MyGenericArray<char>(5);
         
         //setting values
         for (int c = 0; c < 5; c++) {
            charArray.setItem(c, (char)(c+97));
         }
         
         //retrieving the values
         for (int c = 0; c< 5; c++) {
            Console.Write(charArray.getItem(c) + " ");
         }
         Console.WriteLine();
         
         Console.ReadKey();
      }
   }
}

هنگامی که کد بالا کامپایل و اجرا می شود، نتیجه زیر را ایجاد می کند -

0 5 10 15 20
a b c d e

ویژگی‌های جنریک‌ها (Features of Generics)

جنریک‌ها یک تکنیک هستند که برنامه‌های شما را به روش‌های زیر بهبود می‌بخشند −

  • به شما در بهره‌برداری بیشینه از قابلیت استفاده مجدد کد، ایمنی نوع و عملکرد کمک می‌کند.

  • شما می‌توانید کلاس‌های مجموعه جنریک بسازید. کتابخانه کلاس .NET Framework حاوی چندین کلاس مجموعه جنریک جدید در فضای‌نام System.Collections.Generic است. شما می‌توانید از این کلاس‌های مجموعه جنریک به جای کلاس‌های مجموعه در فضای‌نام System.Collections استفاده کنید.

  • شما می‌توانید رابط‌ها، کلاس‌ها، متدها، رویدادها و delegate‌های جنریک خود را بسازید.

  • شما می‌توانید کلاس‌های جنریک خود را با محدودیت‌هایی ایجاد کنید تا به شما اجازه دسترسی به متدها بر روی انواع داده‌های خاص را بدهد.

  • شما می‌توانید با استفاده از بازتاب (reflection)، در زمان اجرا اطلاعاتی درباره انواع استفاده شده در یک نوع داده جنریک دریافت کنید.

متدهای جنریک (Generic Methods)

در مثال قبل، از یک کلاس جنریک استفاده کردیم؛ می‌توانیم یک متد جنریک با پارامتر نوع اعلام کنیم. برنامه زیر مفهوم را نشان می‌دهد −

using System;
using System.Collections.Generic;

namespace GenericMethodAppl {
   class Program {
      static void Swap<T>(ref T lhs, ref T rhs) {
         T temp;
         temp = lhs;
         lhs = rhs;
         rhs = temp;
      }
      static void Main(string[] args) {
         int a, b;
         char c, d;
         a = 10;
         b = 20;
         c = 'I';
         d = 'V';
         
         //display values before swap:
         Console.WriteLine("Int values before calling swap:");
         Console.WriteLine("a = {0}, b = {1}", a, b);
         Console.WriteLine("Char values before calling swap:");
         Console.WriteLine("c = {0}, d = {1}", c, d);
         
         //call swap
         Swap<int>(ref a, ref b);
         Swap<char>(ref c, ref d);
         
         //display values after swap:
         Console.WriteLine("Int values after calling swap:");
         Console.WriteLine("a = {0}, b = {1}", a, b);
         Console.WriteLine("Char values after calling swap:");
         Console.WriteLine("c = {0}, d = {1}", c, d);
         
         Console.ReadKey();
      }
   }
}

هنگامی که کد بالا کامپایل و اجرا می شود، نتیجه زیر را ایجاد می کند -

Int values before calling swap:
a = 10, b = 20
Char values before calling swap:
c = I, d = V
Int values after calling swap:
a = 20, b = 10
Char values after calling swap:
c = V, d = I

delegate‌های جنریک (Generic Delegates)

شما می‌توانید با استفاده از پارامترهای نوع، delegate‌ی جنریک را تعریف کنید. به عنوان مثال −

delegate T NumberChanger<T>(T n);

مثال زیر استفاده از این نماینده - را نشان می دهد

using System;
using System.Collections.Generic;

delegate T NumberChanger<T>(T n);
namespace GenericDelegateAppl {
   class TestDelegate {
      static int num = 10;
      
      public static int AddNum(int p) {
         num += p;
         return num;
      }
      public static int MultNum(int q) {
         num *= q;
         return num;
      }
      public static int getNum() {
         return num;
      }
      static void Main(string[] args) {
         //create delegate instances
         NumberChanger<int> nc1 = new NumberChanger<int>(AddNum);
         NumberChanger<int> nc2 = new NumberChanger<int>(MultNum);
         
         //calling the methods using the delegate objects
         nc1(25);
         Console.WriteLine("Value of Num: {0}", getNum());
         
         nc2(5);
         Console.WriteLine("Value of Num: {0}", getNum());
         Console.ReadKey();
      }
   }
}

هنگامی که کد بالا کامپایل و اجرا می شود، نتیجه زیر را ایجاد می کند -

Value of Num: 35
Value of Num: 175