PDA

View Full Version : سوال: لیست جنریک چیست و چه کاربردی داره؟



BestLover
چهارشنبه 02 بهمن 1387, 22:10 عصر
سلام
از عنوان تاپیک معلوم هست که چی می خوام. البته یک مقاله در سایت پیدا کردم که چیز زیادی از اون متوجه نشدم. در ضمن کاربردهای این لیست ها برام خیلی مهمه.

با تشکر

Ali_Mor
پنج شنبه 03 بهمن 1387, 08:35 صبح
تا جائی که من می دونم یک لیست از عناصر که نوعی خاص دارند، کمی شبیه ارایه
البته مثل آرایه تعداد عناصرش ثابت نیست و به راحتی می توانید عنصر جدید را به ان Add کنید
بطورکلی کلاس های جنریک براساس نوعی که برای آنها با کلمه کلیدی Of تعیین می شود ، شکل خود را در زمان اجرا بوجود می آورند(این تعریف من در آوردی است). مثلا کلاسی برای سورت آرایه نوشته اید. سوال اینجاست که این کلاس آرایه از چه نوعی را مرتب می کند(integer, String , ...) . اگر کلاس خود را از نوع جنریک بنویسید آنگاه کارتان خیلی راحت می شود
لیست جنریک هم مانند کالکشنی است که نوع عناصر آن براساس خواست شما تعیین می شود
مثلا لیستی از رشته ها:
Dim strArr as list(of string)

BestLover
پنج شنبه 03 بهمن 1387, 14:00 عصر
ممنمون از جوابتون.
یعنی لیست جنریک تقریبا شبیه لیست های پیوندی در ساختمان داده هست؟

Ali_Mor
جمعه 04 بهمن 1387, 13:01 عصر
اگر بگیم یه چیزی مثل آرایه پویا بهتر است، تعریف دقیق لیست جنریک اینه
Represents a strongly typed list of objects that can be accessed by index. Provides methods to search, sort, and manipulate lists.

چون دانت نت یک کلاس جنریک برای لیست های پیوندی دارد
Dim lnk As New LinkedList(Of String)

BestLover
شنبه 05 بهمن 1387, 00:28 صبح
با این اوصاف این لیست جنریک چه مزییتی داره؟
چون هم ارایه هست و هم لیست پیوندی.
در ضمن نحوه تعریف کردن یک لیست جنریک چگونه هست؟
به نظر باید شبیه همین لست پیوندی باشه.

Mehdi Asgari
شنبه 05 بهمن 1387, 01:28 صبح
ریشۀ اولیه اش رو نمی دونم ، ولی Generic programming با سی پلاس پلاس رواج پیدا کرد. "لیست" صرفا یک مثال از هزاران مثالیه که در برنامه نویسی جنریک میشه زد. البته در دات نت میگیم Generics و در سی پلاس پلاس Template. (زبان های داینامیک و تابعی بمانند)
از مثال قدیمیش شروع می کنم. فرض کن میخوای یه کلاس بسازی که پشته (Stack) رو پیاده سازی کنه. (اگه نمی دونی پشته چیه ، همین الان این صفحه رو بی خیال شو و برو در موردش جستجو و مطالعه کن). با توجه به پر کاربرد بودن اعداد صحیح (Integer) در برنامه نویسی بالطبع اول کدت به این شکل خواهد بود: (کد ها رو در ساده ترین و کوتاه ترین شکل ممکن نوشتم. به جزئیاتش زیاد توجه نکن چون هدف چیز دیگری است)



‘VB
Class MyStack
Private internal_array(10000) As Integer
Private index As Integer = 0
Public Sub Push(ByVal value As Integer)
internal_array(index) = value
index += 1
End Sub
Public Function Pop() As Integer
index -= 1
Return internal_array(index)
End Function
End Class

//C#
class MyStack
{
private int[] internal_array = new int[10000];
private int index = 0;
public void Push(int value)
{
internal_array[index++] = value;
}
public int Pop()
{
return internal_array[--index];
}
}

خب حالا چند روز بعد متوجه میشی که علاوه بر اعداد صحیح باید بتونی اعداد اعشاری و رشته ها رو هم در پشته ذخیره کنی. دو راه داری:
1- دو تا کلاس دیگه عین کلاس بالا درست کنی که کپی همین باشن ، فقط هر جا Integer داشتی به جاشون نوع دلخواه رو جایگزین کنی . مشکل: یکی از اصلی ترین اصول برنامه نویسی زیر سوال میره. Code Reuse . با این کار داری کد مشابه رو هی duplicate می کنی. حالا فکر کن بعدا قرار بشه هزار تا نوع دیگه هم به پشته اضافه کنی!
2- بیای به جای Integer از Object استفاده کنی و خوشحال باشی که Object مادر تمام اشیاست و تو به راحتی می تونی هر نوع شی ای (مقداری) رو در یک object بگنجونی. مشکل: اول به دلیل boxing کدت مشکل پرفورمنس خواهد داشت (در جاهای خفن. مثلا بازی) دوم: باید همه اش از casting استفاده کنی. سوم: فرض کن اگه Object رو نداشتی چیکار می کردی ؟ چهارم: احتمال خطا و type mismatch و در نتیجه خطاهای زمان اجرا هست. پنجم فعلا به ذهنم نمی رسه.
برای مقابله با این مسائل که تو بتونی از یک کد جنریک یا کلی برای یک کلاس از مسائل مشابه استفاده کنی ، موجوداتی به نام Generics (templates) آفریده شدن. کد زیر یک پشته طراحی می کنه که توش هر چی میشه ریخت



‘ VB
Class MyStack(Of T)
Private internal_array(10000) As T
Private index As Integer = 0
Public Sub Push(ByVal value As T)
internal_array(index) = value
index += 1
End Sub
Public Function Pop() As T
index -= 1
Return internal_array(index)
End Function
End Class
// C#
class MyStack <T>
{
private T[] internal_array = new T[10000];
private int index = 0;
public void Push(T value)
{
internal_array[index++] = value;
}
public T Pop()
{
return internal_array[--index];
}
}


نحوۀ استفاده:



‘ VB
Dim s As New MyStack(Of Integer)
s.Push(10)
s.Push(9)
Console.WriteLine(s.Pop())
Console.WriteLine(s.Pop())
// C#
MyStack<int> s = new MyStack<int>();
s.Push(90);
s.Push(-8);
Console.WriteLine(s.Pop());
Console.WriteLine(s.Pop());

حالا هر نوع شی ای رو که بخوای می تونی داخل این پشته قرار بدی.
خب حالا که مفهوم رو فهمیدی برسیم به سوالت:
لیست که مطمئنا می دونی چیه. لیست جنریک لیستیه که خودت موقع تعریف یک شی ازش میگی که قراره چه نوع داده هایی درش ذخیره بشن. و مشکل runtime exception هم نداری
مثال: لیستی از اعداد ، رشته ها و ArrayList ها



'VB
Dim s = "Hello"
Dim t = "World"
Dim strList = New List(Of String)()
strList.Add(s)
strList.Add(t)

Dim i = 100
Dim j = -6
Dim intList = New List(Of Integer)()
intList.Add(i)
intList.Add(j)

Dim f1 = New ArrayList()
Dim f2 = New ArrayList()
Dim arrList = New List(Of ArrayList)()
arrList.Add(f1)
arrList.Add(f2)
//C#
string s = "Hello";
string t = "World";
var strList = new List<string>();
strList.Add(s);
strList.Add(t);
int i = 100;
int j = -6;
var intList = new List<int>();
intList.Add(i);
intList.Add(j);
var f1 = new ArrayList();
var f2 = new ArrayList();
var arrList = new List<ArrayList>();
arrList.Add(f1);
arrList.Add(f2);


به جنریکس ، Parameterized types هم میگن ؛ یعنی انواع داده ای که پارامتر دارن. (اون پارامتر همون T هست که هر دفعه یه چیز به جاش میدی. مثلا وقتی از Integer استفاده می کنی ، در پیاده سازی کدت به جای T ، نوع Integer قرار خواهد گرفت) دیگه در لیستی از نوع Integer نمی تونی یک رشته قرار بدی (در حالی که اگه از نوع Object بود هرچی می تونستی توش بریزی و بعدا موقع unboxing مشکل پیدا می کردی)
پ ن 1: مطمئنا به همین سادگی ها نبود. ولی فکر کنم مفهوم رو گرفته باشی. همین Generics به تنهایی یک کتاب رو به خودش اختصاص داده: Professional .NET 2.0 Generics (پس از کمی ور رفتن و مطالعه ، مشکلات پیشرفته تر و سخت ترت رو می تونی بپرسی)
پ ن 2: بیش از سوالت جواب دادم تا در آینده کسی سوال مشابهی مثلا در مورد صف جنریک داشت ، تاپیک جدید ایجاد نکنه. کد ها رو هم دوزبانه کردم که کاربران سی شارپ هم بتونن استفاده کنن

mostafaaa
شنبه 05 بهمن 1387, 09:54 صبح
سلام دوست من
از جواب کاملی که به دوستمون دادی ممنون ، مطمعنم که برای برنامه نویسهای تازه کار خیلی میتونه مفید باشه.
فقط یه نکته کوچیک اینه که در پیاده سازی کلاس پشته منطقی نیست که از آرایه استفاده بکنیم، کلاس پشته خودش یه ساختمان داده است و ما با توجه به اینکه در این کلاس آخرین عنصری که به کلاس اضافه میشه آدرس عنصر ماقبلش رو داره باید کلاس رو پیاده سازی بکنیم.
شاید این کد که میزارم کمی منطقی تر باشه باشه :

Public Class MyStack(Of T)
Private Value As Object
Private Top As MyStack(Of T) = Nothing
Private Pri As MyStack(Of T) = Nothing
Private _Count As Integer = 0
Public Sub Push(ByVal Value As T)
If Top Is Nothing Then
Top = New MyStack(Of T)
Top.Value = Value
Else
Top.Top = New MyStack(Of T)
Top.Top.Pri = Top
Top = Top.Top
Top.Value = Value
End If
_Count += 1
End Sub
Public Function Peek() As Object
Return Top.Value
End Function
Public Function Pop() As Object
Dim Temp As Object = Top.Value
Top = Top.Pri
_Count -= 1
Return Temp
End Function
Public ReadOnly Property Count() As Integer
Get
Return _Count
End Get
End Property
End Class

یا علی

Mehdi Asgari
یک شنبه 06 بهمن 1387, 13:35 عصر
نمی دونم به چی میگی "منطقی" ، ولی در دات نت از این روش برای پیاده سازی کلاس Stack استفاده شده