PDA

View Full Version : کلاس های جنریک



hadafeayandeh
سه شنبه 31 مرداد 1391, 16:27 عصر
کلاس های جنریک (عمومی) کلاس هایی هستند که از آنها می توان برای انواع داده های متفاوت استفاده کرد.
قبل از این که به بحث کلاس های عمومی بپردازیم بهتر است به توابع عمومی (جنریک) نگاهی بیندازیم. به یک مثال توجه کنید. فرض کنید می خواهیم یک تابع به نام sum برای جمع کردن دو عدد ورودی بنویسیم. توابع زیر می توانند برای این منظور تعریف شوند:
public int sum( int a, int b)
{
return (a + b);
}

public double sum( double a, double b)
{
return (a + b);
}

public byte sum( byte a, byte b)
{
return (a + b);
}
وقتی که این سه تابع را تعریف می کنیم، هنگامی که تابع sum را با پارامترهایی از نوع int فراخوانی می کنیم، تابع اول فراخوانی می شود. اگر همین تابع sum را با پارامترهایی از نوع double فراخوانی کنیم، تابع دوم فراخوانی می شود و ... . در اینجا ما سه بار تابع sum را تعریف کرده ایم.
در توابع عمومی (جنریک) می توان تابع فوق را یک بار و به صورت زیر تعریف کرد:
public double sum(T a, T b)
{
if( typeof(T) == typeof(int))
{
return (double)( Convert.ToInt32(a) + Convert.ToInt32(b));
}
if( typeof(T) == typeof(double))
{
return Convert.ToDouble(a) + Convert.ToDouble(b);
}
if( typeof(T) == typeof(byte))
{
return (double)( Convert.ToByte(a) + Convert.ToByte(b));
}
return 0;
}
حالا برای فراخوانی تابع sum می توانیم از دستور زیر استفاده کنیم:
double result = sum(12.509, 49.4);

همانطور که می بینید با توجه به ورودی تابع که بین < >قرار گرفته است، پارامترهای تابع متناسب با آن عمل می کنند. در این مثال شاید دو سوال ذهن شما را درگیر کرده باشد: 1- کد تابع sum نسبت به قبل پیچیده تر شده است. 2- خروجی برای تمام ورودی ها از نوع double است.
در پاسخ به این سوالات باید گفت که با توجه به مثالی که ذکر شده و با توجه به عملی که در این تابع انجام می شود (یعنی عمل جمع) کد تابع کمی پیچیده شده است ولی در مورد توابعی که در ادامه خواهیم گفت، فوق العاده کار را ساده می کنند. و اما در مورد سوال دوم. خروجی تابع sum می تواند از نوع T باشد. یعنی اپر کاربر هنگام فراخوانی تابع sum به صورت sum(12, 20); ž عمل کند خروجی نیز از نوع short بشود ولی در این مثال فقط برای سادگی کار این عمل را انجام ندادیم.

در مورد کلاس های جنریک هم قضیه به همین صورت است. مثال زیر یک کلاس جنریک را که برای گره لیست پیوندی نوشته شده است را نشان می دهد:
public class Node
{
public T data;
public T next;

public Node(T value)
{
data = value;
next = null;
}
}
اگر همین کلاس را می خواستیم برای انواع داده مختلف تعریف کنیم، کار بسیار دشواری پیش رو داشتیم. اگر برای همین کلاس بخواهیم تعیین کنیم که ورودی کلاس (یعنی T) از نوع داده های عددی باشد، یعنی int, double, byte, short, single و ... می توانیم خط اول کلاس را به صورت زیر تغییر دهیم:
public class Node where T: struct
{
//...
}
خط اول تعریف بالا به کامپایلر سی شارپ می گوید که ورودی تعیین شده (یعنی T) فقط باید از انواع داده ای عددی (یا به طور تخصصی تر انواع داده هایی که valued-type هستند و نه referenced-type) باشد.

برای توضیح بیش تر به کلاس لیست پیوندی تعریف شده زیر توجه کنید (توضیحات به خود شما واگذار می شود!):
public class Node where T : struct
{
public T data;
public Node next;
public Node(T value)
{
data = value;
next = null;
}
}

public class myLinkedList where Y : struct
{
private Node head, cur, end;
public int Count;

public myLinkedList()
{
// set head, cur and end to null
head = cur = end = null;
// count contains count of items available in the list
Count = 0;
}

public void Add(Y newValue)
{
// if there is not any data create head of list
if (head == null)
{
head = end = new Node(newValue);
}
else
{
end.next = new Node(newValue);
end = end.next;
}
Count++;
}

public Y[] ToArray()
{
Y[] result = new Y[Count];
cur = head;
int i = 0;
while (cur != null)
{
result[i] = cur.data;
cur = cur.next;
}
return result;
}
}



+ (http://linq-class-csharp.blogfa.com/post-7.aspx) نوشته شده توسط رضا بیات در یکشنبه بیست و دوم آذر 1388 و ساعت 10:6 | نظر بدهید


http://www.blogfa.com/layouts/shamim/puce_menu.gifجزئیات بیشتری در مورد کلاس ها (http://linq-class-csharp.blogfa.com/post-5.aspx)
در تعریف کلاس ها می توان یک سری کلمه کلیدی را به کار برد که به کلاس مورد نظر ویژگی خاصی را می دهند. مثلا استفاده از کلمه کلیدی abstract باعث می شود که نتوان از کلاس مورد نظر مشتق شد.

1. کلمه کلیدی abstract
استفاده از این کلمه به این معنی است که نمی توان از این کلاس مشتق شد و این کلاس فقط می تواند به عنوان کلاس پایه برای دیگر کلاس ها استفاده شود. البته مطلب دوم شاید کاملا صحیح نباشد که در ادامه توضیح خواهیم داد. برای مثال به کدهای زیر توجه کنید.
public abstract class A
{
public int SomeProperty { get; set; }
}

....
A myA = new A();
به دلیل این که کلاس A به صورت abstract تعریف شده است، نمی توان یک شیئ از این کلاس را تعریف کرد. پس خط آخر دستورات گفته شده، باعث بروز خطا هنگام کامپایل برنامه خواهد شد. در صورتی که بخواهیم از کلاس A استفاده کنیم می توانیم به صورت زیر عمل کنیم:
public class B : A
{
public int OtherProperty { get; set; }
}

....
B myB = new B();
myB.SomeProperty = 12;
myB.OtherProperty = 20;
2. کلمه کلیدی sealed:
این کلمه کلیدی دقیقا برعکس کلمه کلیدی Abstract عمل می کند. یعنی اگر کلاسی به صورت sealed تعریف شود، نمی توان از این کلاس مشتق شد و برای استفاده باید یک شئی جدید از این کلاس تعریف کرد. نحوه تعریف و استفاده از این کلاس ها به صورت زیر است:
public sealed class mySealed
{
public double P1 { get; set; }
}

...
mySealed m = new mySealed();
m.P1 = 50.7345;
3. کلمه کلیدی static:
در صورتی که کلاس به کلمه کلیدی static معرفی شود، اعضای آن بدون نمونه سازی از کلاس (تعریف شیئ جدید) قابل دسترسی هستند. البته تمام مشخصه ها و توابع باید به صورت static تعریف شوند. به مثال زیر توجه کنید:
public static class myClass
{
public static int myValue { get; set; }
public static int Square()
{
return (myValue * myValue);
}
}

...
myClass.myValue = 7;
int s = myClass.Square();
استفاده از دستور زیر باعث بروز خطا در زمان کامپایل می شود:







myClass m = new myClass();
m.myValue = 7;
int s = m.Square();










از کلمه کلید static می توان استفاده های جالبی کرد. مثلا اگر یک مشخصه یا یک تابع در یک کلاس به صورت static تعریف شود، بدون نمونه سازی از کلاس می توان به آن دسترسی داشت. در مثال زیر کلاس A به صورت static تعریف نشده است ولی بدون نمونه سازی از کلاس می توان به تابع Add دسترسی داشت.
public class A
{
public static int myValue {get; set; }
public static Add(int a, int b)
{
return (a + b);
}
}

...
int m = A.Add(12, 40);
همچنین می توان از دستورات زیر استفاده کرد:
A myA = new A();
imt m = myA.Add (12, 40);
نکته قابل توجه این است که در صورتی که مقدار یک مشخصه static تغییر کند، این مقدار در تمام برنامه تغییر خواهد کرد. از این نکته می توان برای ارسال اطلاعات از یک فرم به فرم دیگر در سی شارپ استفاده کرد.

3. کلمه کلیدی partial:
استفاده از این به کامپایلر می گوید که کد های ذکر شده در اینجا فقط بخشی از کدهای کلاس اصلی است. یعنی می توان کد های کلاس را در چند کلاس مجزا نوشت. در دات نت، تمامی کلاس های فرم به صورت partial تعریف می شوند. به مثال زیر توجه کنید:
public partial class myClass
{
public int P1 { get; set; }
}

...
public partial class myClass
{
public int P2 { get; set; }
}

...
myClass mc = new myClass();
mc.P1 = 39;
mc.P2 = 86;
همانطور که مشاهده می کنید بخشی از کد های کلاس myClass در یک جا و ادامه کدها در قسمت دیگری آمده است. از این ویژگی می توان برای گسترش کلاس ها استفاده کرد.
آموزش سی شارپ (http://www.tahlildadeh.com/CourseDetails/55/Elementary-Csharp.aspx)