نحوه استفاده از کلاس های Generics در سی شارپ

یکی از قدرتمندترین و زیبا ترین قابلیت ها در زبان برنامه نویسی سی شارپ Genericها هستند که مکانیزمی برای طراحی کلاس ها، متدها و Interface ها می باشند. با استفاده از Generic ها می توانید یک تمپلیت از کلاس، متد و ... ایجاد نموده و آن را به روش های دلخواه پیاده سازی نمایید.

متدهای Generic

استفاده از Genericها در سطوح متوسط و بالای برنامه نویسی موجب افزایش بهره وی و سهولت توسعه برنامه های مختلف می شوند. برای مثال فرض کنید قصد دارید متدی جهت نمایش اطلاعات ایجاد نمایید بطوریکه بتوان مقادیر مختلفی مانند int, string, char و ... به آن ارسال نمود.

در نگاه اول شاید مفهوم سربارگذاری متدها به عنوان راه حل به ذهن شما خطور کند بطوریکه متدی با نام یکسان اما ورودی های متفاوت تعریف کرد. این روش هرچند قابل پیاده سازی می باشد اما برای پیاده سازی متدی که همه نوع اطلاعات را دریافت نماید راه مناسبی نمی باشد زیرا به ازای هر نوع اطلاعات ورودی (مانند  int, string و ...) می بایست یک overload برای آن تعریف نمود.

با استفاده از Generic ها می توان یک تمپلیت کلی تعریف نمود بطوریکه با ارسال هر نوع اطلاعاتی به آن، متناسب با نوع داده ورودی عمل کند.

نحوه تعریف یک متد Generic به شکل زیر می باشد.

public static void ShowValue<T> (T value)
{
    Console.WriteLine(value.ToString());
}

در این مثال یک متد Generic به نام ShowValue تعریف شده است. بعد از نام متد عبارت   <T> قرار داده شده است و پارامتر Value آن نیز از نوع T می باشد. همانطور که پیش تر گفته شد، با استفاده از Generic ها یک Template تعریف می شود که این Template با هر نوع اطلاعاتی قابل استفاده می باشد. یعنی اگر هنگام پیاده سازی ShowValue آن را از نوع int در نظر بگیریم، value از نوع int خواهد بود و اگر از نوع string تعریف شود، value از نوع string در نظر گرفته می شود.

پس از تعریف متد Generic می توان آن را به شیوه های دلخواه پیاده سازی کرد. برای مثال اگر قصد داشته باشید متد مورد نظر از نوع int باشد می بایست به شکل زیر عمل کنید.

ShowValue<int>(25);

همانطور که مشاهده می کنید، هنگام پیاده سازی متد، داخل علامت های < > نوع اطلاعات (data type) تعیین می گردد. کد کامل این مثال به شکل زیر خواهد بود.

static void Main(string[] args)
{
    ShowValue<int>(25);
    Console.ReadLine();
}
public static void ShowValue<T> (T value)
{
    Console.WriteLine(value.ToString());
}

نکته: در برنامه های کنسول اگر قصد داشته باشید در کلاس Program که کلاس اصلی برنامه می باشد متد تعریف نمایید، متد مورد نظر می بایست از نوع static باشد زیرا متد Main یک متد static بوده و اگر قصد داشته باشید از متدی داخل آن استفاده نمایید، می بایست متد مورد نظر نیز از نوع static باشد.

کلاس های Generic

نحوه تعریف کلاس های Generic نیز شباهت زیادی به متدهای Generic دارد. برای مثال فرض کنید قصد داریم کلاسی به نام MyArray ایجاد نماییم که حاوی دو متد برای پر کردن و نمایش اطلاعات درون آرایه باشد. در بخش آرایه ها نحوه ساخت آرایه ای از نوع int, string و ... آموزش داده شد. با استفاده از Generic ها می توان آرایه های قابل انعطاف تری ایجاد نمود بطوریکه بتوان هر نوع اطلاعاتی را درون آن ذخیره نمود و محدود به یک نوع خاص نباشد.

برای حل این مثال کلاس MyArray را به پروژه خود اضافه کنید.

class MyArray
{

}

در قدم اول می بایست این کلاس را به یک کلاس Generic تبدیل کنیم.

class MyArray<T>
{

}

حال باید درون این کلاس آرایه از از نوع T تعریف شود.

public class MyArray<T>
{
    private T[] array;
}

در متد سازنده می توان عددی را به عنوان طول آرایه دریافت نموده و آرایه ای متناسب با آن ایجاد نمود.

public class MyArray<T>
{
    private T[] array;
    public MyArray(int size)
    {
        array = new T[size];
    }
}

حال می توان متدهای مربوط به پرکردن آرایه و نمایش اطلاعات را پیاده سازی نمود.

public class MyArray<T>
{
    private T[] array;
    public MyArray(int size)
    {
        array = new T[size];
    }
    public void SetItem(int index, T value)
    {
        array[index] = value;
    }
    public T GetItem(int index)
    {
        return array[index];
    }
}

در متد SetIndex دو پارامتر تعیین شده است که اولی اندیس آرایه و دومی مقداری که قصد داریم در محل تعیین شده قرار دهیم. وظیفه متد GetItem نیز برگردادن محتوای خانه مورد نظر می باشد.

پس از ساخت کلاس مربوط به آرایه می توان از آن درون برنامه استفاده نمود. بدین منظور می بایست از کلاس MyArray یک نمونه جدید بسازید.

MyArray<int> numbers = new MyArray<int>(5);

در این مثال آرایه ای از نوع int و با طول 5 ایجاد شده است. حال می توان با استفاده از حلقه for خانه های آرایه را مقداردهی نمود.

static void Main(string[] args)
{
    MyArray<int> numbers = new MyArray<int>(5);
    //fill array
    for (int i = 0; i < 5; i++)
    {
        Console.Write("Please enter a number: ");
        int num = int.Parse(Console.ReadLine());
        numbers.SetItem(i, num);
    }
}

برنامه نمایش محتوای آرایه نیز نیاز به یک حلقه for دیگر می باشد.

static void Main(string[] args)
{
    MyArray<int> numbers = new MyArray<int>(5);
    //fill array
    for (int i = 0; i < 5; i++)
    {
        Console.Write("Please enter a number: ");
        int num = int.Parse(Console.ReadLine());
        numbers.SetItem(i, num);
    }
    //show data
    for (int i = 0; i < 5; i++)
    {
        Console.Write(numbers.GetItem(i) + ", ");
    }
    Console.ReadLine();
}

مطلب تکمیلی مبحث Genericها در مقاله بعدی (Collections) می باشد که با ترکیب این دو قابلیت می توان عملیات متنوعی بر روی اطلاعات انجام داد و استفاده از آنها در ساخت اپلیکیشن هایی که با پایگاه داده در ارتباط می باشند کاربرد فراوانی دارد.