PDA

View Full Version : سوال: چرا وقتی یک متد رو مستقیما می شه صدا کرد اونو بهDelegate می دیم و غیر مستقیم صدا می زنیم



mona11
دوشنبه 11 دی 1391, 15:28 عصر
سلام.چرا من باید یک تابع رو به یک دلیگیت نسبت بدم و بعد بیام اون دلیگیت رو فراخوانی کنم؟خب از همون اول میام اون تابع رو اجرا میکنم دیگه...لطفا یه مثالی بزنید که تنها راه حل استفاده از دلیگیت باشه و نتونیم با فراخوانی مستقیم تابع اون الگوریتم رو بنویسیم...

gwbasic
دوشنبه 11 دی 1391, 15:51 عصر
اگه بتونیم مستقیما اون تابع رو صدا کنیم که هیچ وقت این کارو نمی کنیم!
این حالت وقتی پیش می یاد که نمی تونیم مستقیما اون متد رو صدا بزنیم. یک مثال ساده همون رویداد کلیک یک button هست. کسی که button رو نوشته نمی دونه که وقتی روی اون کلیک شد چه اتفاقی قرار بیافته بنابراین اصطلاحا اونو delegate می کنه به client یعنی جایی که از button استفاده میشه! client که می دونه مثلا باید بعد از کلیک قرار عمل ذخیره انجام بشه. عمل ذخیره رو داخل یک متد می نویسه و به رویداد کلیک اون باتن Attach می کنه.
امیدوارم موضوع جا افتاده باشه

خواهشا از عنوان کاملتری استفاده کنید

tooraj_azizi_1035
دوشنبه 11 دی 1391, 16:15 عصر
اگه شما می تونستی یک تابع یا متد رو به عنوان پارامتر به یک تابع یا متد دیگه ارسال کنی بدون استفاده از Delegate در این صورت وجود Delegate احمقانه بود. اما چون امکان پذیر نیست پس وجودش مفیده.

شما نمی تونی متدی بنویسی در اون متد خود شرط به عنوان یک پارامتر به متد ارسال بشه.
البته این فقط یکی از دلایل وجودی Delegate است.

متدی که یک تابع به عنوان پارامتر به اون ارسال میشه:

private static int HowManyHoursInTheFirstYear(IList<DateTime> samples, Func<DateTime, DateTime, bool> comparer)
{
DateTime firstDate = samples[0].Date;
int count = 0;
while (count < samples.Count && comparer(samples[count], firstDate) ) {
count++;
}
return count;
}



فراخوانی:


HowManyDaysInTheFirstPeriod(samples, (d1, d2) = > { return d1.Month == d2.Month; });
HowManyDaysInTheFirstPeriod(samples, (d1, d2) = > { return d1.Year == d2.Year; });

mona11
دوشنبه 11 دی 1391, 21:52 عصر
ببینید مثلا من میخوام مقدار برگشتی تابع f1 ، به عنوان پارامتر ورودی تابع f2 استفاده بشه.فرض کنید تابع f1 به ما یک رشته برمیگردونه پس طبیعتا نوع اون تابع باید string تعریف شه...خب حالا من مینویسم

string s1=f1();


حالا s1 رو میدم به عنوان پارامتر تابع f2
انگار من از تابع f1 به عنوان ورودیِ تابع f2 استفاده کردم...

plus
دوشنبه 11 دی 1391, 22:00 عصر
ببینید مثلا من میخوام مقدار برگشتی تابع f1 ، به عنوان پارامتر ورودی تابع f2 استفاده بشه.فرض کنید تابع f1 به ما یک رشته برمیگردونه پس طبیعتا نوع اون تابع باید string تعریف شه...خب حالا من مینویسم

string s1=f1();


حالا s1 رو میدم به عنوان پارامتر تابع f2
انگار من از تابع f1 به عنوان ورودیِ تابع f2 استفاده کردم...

توی این حالت، اگه تابع f2 نیاز داشته باشه که یک پارامتری به تابع f1 بده و خروجی ش رو بگیره شما نمیتونی این کار رو بکنی چون نمیدونی f2 چه پارامتری میخواد به f1 بده.

mona11
دوشنبه 11 دی 1391, 22:13 عصر
توی این حالت، اگه تابع f2 نیاز داشته باشه که یک پارامتری به تابع f1 بده و خروجی ش رو بگیره شما نمیتونی این کار رو بکنی چون نمیدونی f2 چه پارامتری میخواد به f1 بده.
آهااااا...حالا فهمیدم.حالا میشه همین توضیحی که دادینو با کد بیانش کنید.یعنی با delegate بنویسیدش لطفا

plus
دوشنبه 11 دی 1391, 22:40 عصر
توی این مثال، ما کلاسی به اسم User داریم و یک آرایه ازین کلاس داریم.حالا ما متدی داریم که قرار آرایه رو بگیره و مرتب کنه (f2).این متد برای برای مرتب کردن آرایه، نیاز به مقایسه User ها داره.واسه همین یک delegate میگیره تا اون، کار مقایسه رو براش انجام بده:

public class User
{
public User(string Name, int Age)
{
this.Name = Name;
this.Age = Age;
}
public string Name
{
get;
set;
}
public int Age
{
get;
set;
}
}

public delegate int UserComparer(User user1, User user2);

public void SortUsers(User[] users, UserComparer comparerMethod)
{
long right_border = users.Length - 1;
long last_exchange = 0;
do
{
last_exchange = 0;
for (long i = 0; i < right_border; i++)
{
if (comparerMethod(users[i], users[i + 1]) > 0)
{
User temp = users[i];
users[i] = users[i + 1];
users[i + 1] = temp;

last_exchange = i;
}
}
right_border = last_exchange;
}
while (right_border > 0);
}

public int UserComparerMethod(User user1, User user2)
{
return user1.Name.CompareTo(user2.Name);
}

private void Form1_Load(object sender, EventArgs e)
{
User[] users = new User[3]
{
new User("Betty", 23),
new User("Susan", 20),
new User("Lisa", 25)
};

SortUsers(users, UserComparerMethod);
}

متدی که ما بهش برای مقایسه میدیم، دو تا User میگیره و اونها رو بر اساس نام مقایسه میکنه.در این حالت، متد Sort در مورد نحوه مقایسه نیاز نیست چیزی بدونه و نحوه مقایسه بستگی به delegate ی داره که ما بهش میدیم. ممکنه یکجا بخوایم بر اساس سن مرتب کنیم. میتونیم یک method در قالب delegate تعریف شده بهش بدیم که بجای نام از سن برای مقایسه استفاده کنه..
پ.ن : البته در #C برای مقایسه یک آرایه از هر نوع، روش بهتری هست من فقط برای مثال delegate این کد رو نوشتم...

mona11
دوشنبه 11 دی 1391, 23:13 عصر
پس شما منظورتون اینه که آقا برای اینکه بتونیم از یک تابع داخل تابعی دیگه استفاده کنیم باید delegate بنویسیم.یعنی نمیشه یک تا بع مثلا f1 رو داخل بدنه ی تابع دیگه ای به نام (f2) فراخوانی کرد.درست فهمیدم؟ :)
مثلا تو همین کدی که شما گذاشتین،تابع UserComparerMethod در تابع SortUsers فراخوانی شده که این فراخوانی باید توسط یک delegate انجام بگیره :)

plus
دوشنبه 11 دی 1391, 23:29 عصر
بله.وقتی یک متد (یا یک رویداد مثلا TextChanged مربوط به TextBox) نیاز به یک یک متد در قالب خاصی داشته باشه، آدرس اون متد و اون قالب خاص رو delegate مشخص میکنه.البته امکانات #C خیلی زیاده و میشه از روش های دیگه ای هم استفاده کرد.میتونین MSDN رو بررسی کنید. http://msdn.microsoft.com/en-us/library/ms173171(v=vs.100).aspx

mona11
دوشنبه 11 دی 1391, 23:36 عصر
ممنون جناب.لطف کردید.