آموزش برنامه نویسی

آموزش سی شارپ

آموزش سی شارپ

پربیننده ترین مطالب
پیوندهای روزانه

در ادامه آموزش برنامه نویسی به زبان سی شارپ، با مبحث Generics آشنا خواهیم شد. همزمان با بزرگ تر شدن پروژه ای که در حال کار کردن بر روی آن هستید، باید تکنیک هایی را در کد نویسی استفاده کنید که به شما اجازه استفاده مجدد از کدهای نوشته شده را می دهند. یکی از روش های استفاده مجدد از کدهای موجود در موقعیت های مختلف استفاده از قابلیت Generic ها می باشد. این قابلیت به شما اجازه می دهد تا نوع Data Type فیلد ها، خصوصیات و ... برای کلاس ها را زمان ساختن شئ از روی کلاس مشخص کنید. دوستانی که با زبان ++C آشنا هستند، قابلیت Generics در زبان سی شارپ، معادل قابلیت Template ها در زبان ++C است. قابلیت Generics از نسخه 2 به زبان سی شارپ اضافه شد.

ابتدا بیایید ببینیم دنیای بدون Generic ها در زبان سی شارپ چگونه است؟ فرض کنید کلاسی تعریف می کنیم که یک مقدار از نوع int رو داخل خودش نگهداری می کنه:

public class ValueHolder
{
    public int Value { get; set; }
}

در قدم بعدی میخواهیم کلاس دیگری برای نگهداری مقادیر از نوع string ایجاد کنیم:

public class ValueHolder
{
    public string Value { get; set; }
}

اگر بخواهیم برای هر نوع داده یک کلاس جداگانه ایجاد کنیم، کار جالبی نیست، برای حل این مشکل دو راه حل وجود داره، یکی می توانیم کلاس بالا رو تغییر دهیم و نوع داده خاصیت Value رو از نوع object در نظر بگیریم تا هر مقداری داخلش قرار بگیره:

public class ValueHolder
{
    public object Value { get; set; }
}

اما کد بالا مشکلاتی دارد، یکی اینکه با قرار دادن مقادیر از نوع Value Type داخل خصوصیت Value، عملیات Boxing و زمان خواندن مقدار عملیات UnBoxing رخ میدهد که در قسمت قبل گفتیم این دو عملیات باعث کاهش کارآیی برنامه می شوند. همچنین می توان هر مقداری را داخل Value قرار داد که این موضوع مخالف بحث Type Safety می باشد. برای حل این مشکلات، قابلیت Generics به زبان سی شارپ اضافه شد. مثال بالا رو با Generic ها پیاده سازی می کنیم و سپس توضیحات لازم رو خواهیم داد:

public class ValueHolder<T>
{
    public T Value { get; set; }
}

همانطوری که ملاحظه می کنید، در مقابل نام کلاس در میان <>، کاراکتر T نوشته شده، در حقیقت کاراکتر T در اینجا، بیانگر یک جایگاه برای یک متغیر می باشد که در داخل کلاس، به جای نوع داده بای خصوصیت کاراکتر T نوشته شده، در حقیقت ما در کد بالا گفتیم که کلاس ValueHolder یک جایگاه برای نوع داده در نظر می گیرد که ما نام T را برای آن انتخاب کردیم (انتخاب این نام کاملاً اختیاری است، اما بهتر است هر نامی که انتخاب می شود ابتدای آن با کاراکتر T که مخفف Type است شروع شود)، سپس در داخل کلاس و قسمت هایی که قصد داریم نوع داده را زمان ساخت کلاس مشخص کنیم، به جای خود Data Type، کاراکتر T را می نویسیم که در کد بالا برای خصوصیت Value کاراکتر T نوشته شده. در قدم بعدی می بایست از روی کلاس ValueHolder یک شئ بسازیم، اما ساختن شئ در اینجا با حالت عادی تفاوت دارد، برای ساختن شئ از روی کلاس های Generic به صورت زیر عمل می کنیم:

ValueHolder<int> value = new ValueHolder<int>();
value.Value = 12;

همانطور که مشاهده می کنید، در مقابل نام کلاس در زمان ساخت شئ، داخل <> نام Data Type ای را که می خواهیم جایگزین کاراکتر T شود می نویسیم، در کد بالا، خصوصیت Value از نوع int تعریف می شود. علاوه بر نوع داده int، می توانیم هر نوع داده ای را زمان ساخت شئ مشخص کنیم:

ValueHolder<string> stringHolder = new ValueHolder<string>();
stringHolder.Value = "ITPRO.IR";

دقت کنید، زمانی که نوع T را برای مثال، string در نظر گرفتید، دیگر نمی توانید داخل خصوصیت Value، مقادیری غیر از string قرار دهید، مانند اینکه کلاس ValueHolder نوع داده خصوصیت Value را از نوع string در نظر گرفته است.

شما می توانید علاوه بر یک جایگاه برای نوع داده Generic، چندین جایگاه تعریف کنیم. مثال:

public class MultipleGeneric<T1, T2, T3>
{
    public T1 Value1 { get; set; }
    public T2 Value2 { get; set; }
    public T3 Value3 { get; set; }
}

و زمان ساختن شئ از روی کلاس، به صورت زیر عمل می کنید:

MultipleGeneric<int, string, decimal> values = new MultipleGeneric<int, string, decimal>();
values.Value1 = 12;
values.Value2 = "ITPRO.IR";
values.Value3 = 2.5m;

شما علاوه بر اینکه می توانید کلاس ها را به صورت Generic تعریف کنید، امکان تعریف متدها را نیز به صورت Generic دارید. برای مثال، در کد زیر ما یک متد Generic تعریف کردیم که نوع پارامتر های ورودی در زمان صدا زدن متد مشخص می شوند:

public TOut DoSomething<TOut, TParam1, TParam2>(TParam1 param1, TParam2 param2)
{
    return default(TOut);
}

در کد بالا یه جایگاه TOut و TParam1 و TParam2 در نظر گرفتیم و در تعریف متد از آنها استفاده کردیم. حالا زمان فراخوانی متد به صورت زیر عمل می کنیم:

string result = DoSomething<string, int, int>(12, 20);

اما به یک نکته توجه کنید، در داخل بدنه متد، از کلمه کلیدی default مانند یک متد استفاده شده که داخل پرانتز، نام جایگاه TOut را نوشتیم، کلمه کلیدی TOut، مقدار پیش فرض را برای نوع داده مشخص شده برای جایگاه Generic بر می گرداند. در کد بالا، نوع داده string برای TOut مشخص شده و عبارت default مقدار پیش فرض نوع داده string را بر میگرداند.

برای استفاده از نوع داده generic برای متدها در کلاس ها، می توانید از جایگاه های تعریف شده برای کلاس نیز استفاده بکنید:

public class GenericType<T>
{
    public void DoSomething(T param)
    {
            
    }
}

در کد بالا، همانطور که مشاهده می کنید، برای پارامتر ورودی متد، از جایگاه T که در کلاس تعریف کردیم استفاده کردیم. در این قسمت با مباحث اولیه generic ها آشنا شدیم، در قسمت بعدی یکسری نکات کوچک راجع به generic ها را بررسی کرده، با کلاس List آشنا شده و به بررسی Constraint ها در Generics خواهیم پرداخت.

منبع:programming.itpro.ir

  • متین تیماسی ، مبین خسروی و عمران جودکی

نظرات  (۰)

هیچ نظری هنوز ثبت نشده است
ارسال نظر آزاد است، اما اگر قبلا در بیان ثبت نام کرده اید می توانید ابتدا وارد شوید.
شما میتوانید از این تگهای html استفاده کنید:
<b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">
تجدید کد امنیتی