واضح آرشیو وب فارسی:پی سی سیتی: انواع دادهها در زبان سي شارپ
كپي برابر اصل!
http://www.jamejamonline.ir/Media/images/1389/10/26/100833311309.jpg
در زبانهاي قديميمثل C و ++C دادهها هميشه به صورت Value - Type تعريف ميشدند، به اين صورت كه وقتي يك متغير يا يك شيء تعريف ميشود، در حافظه Stack ذخيره شده و در صورت نياز از آن حافظه خوانده ميشود. اما استفاده از Stack و متغيرهاي Value - Type يك مشكل دارند!
فرض كنيد يك تابع نوشتيد كه 2 مقدار int از ورودي گرفته و حاصل جمع آن را در مقدار اول به صورت زير نگه ميدارد:
Void add(int a،int b){
a+=a+b;
}
حال يك تابع، 2 مقدار a و b را به تابع add ميدهد و تابع را به صورت زير فراخواني ميكند.
Int a=10,b=20;
Add(a,b);
Print(a);
انتظاري كه ما داريم اين است كه دستور (printa) مقدار 30 را در خروجي چاپ كند، اما اين اتفاق نميافتد! علت چيست؟
وقتي يك تابع فراخواني ميشود از پارامترهاي ورودياي كه قرار است به تابع داده شود، يك كپي تهيه و به تابع داده ميشود و پس از پايان فراخواني، آن كپي از بين ميرود. سادهتر بگوييم، همين مثال بالا را ببينيد وقتي تابع add فراخواني ميشود، يك كپي از 2 متغير a و b تهيه شده و به تابع add داده ميشود. سپس تابع فراخواني ميشود و زماني كه كار تابع addتمام شده و كنترل را به تابع فراخواننده ميدهد، كپيهاي تهيه شده از متغيرهاي a و bاز بين ميروند. پس هيچ وقت دستور (printa) مقدار 30 را چاپ نميكند. خب، حال مشكل بالا را چگونه حل كنيم؟ به 2 روش ميتوان اين مشكل را حل كرد.
1 ـ مقدار بازگشتي؛ تابع add يك مقدار بازگشتي داشته باشد و زماني كه كارش تمام شد حاصل را به عنوان خروجي برگرداند.
اين روش يك مشكل دارد و آن هم اين است كه دستور return حداكثر يك مقدار بر ميگرداند و اجراي دستور return به منزله اين است كه كار تابع تمام شده است، در نتيجه هيچ وقت نميتوان چند دستور return پشت سرهم داشت. اين روش براي مثال بالا جوابگو است، اما اگر آرگومانهاي ورودي تابع بيشتر از ? تا باشند و مقدار تغير داده شده آنها براي ما مهم باشند ديگر اين روش جوابگو نيست (اين مشكل در زبان سي شارپ قابل حل است، يعني يك تابع چند متغير را برميگرداند، پياده سازي اين روش در سي شارپ بر عهده خواننده گذاشته شده است.)
2 ـ استفاده از اشارهگرها؛ وقتي شما يك متغير اشارهگر تعريف ميكنيد، اين اشارهگر به يك خانه حافظه اشاره دارد و در واقع آدرس آن خانه را در خود نگه ميدارد و هر تغييري در مقدار متغير ميتواند مقدار آن خانه حافظه را تغيير دهد. اما در مورد مشكل بالا، اگر پارامترهاي ورودي يك تابع از نوع اشارهگر باشند، وقتي بخواهيم آن تابع را فراخواني كنيم بايد آدرس متغير را به تابع بدهيم. پس از آن اگر هر تغييري درون تابع روي متغيرهاي ورودي رخ بدهد، چون آدرس متغير بوده، تغييرات در حافظه نوشته ميشود. پس ديگر نگران از بين رفتن تغييرات نيستيم و نيازي هم به استفاده از دستور return براي بازيابي مقدار تغيير داده شده نداريم (البته اين بدان معنا نيست كه يك تابع هيچ مقداري را بر نگرداند، اين امر به نحوه برنامهنويسي شما مربوط است). به اين روش، فراخواني از نوع ارجاع گفته ميشود، يعني به جاي اين كه يك كپي از يك متغير به تابع داده شود، آدرس آن يا ارجاع آن به تابع داده ميشود.
بسيار خب، در زبان سي شارپ متغيرها 2 دسته هستند. دسته اولValue - Type ها هستند كه دقيقا رفتاري مشابه متغيرها در زبان C يا++ C دارند. يعني در Stack ذخيره ميشوند و اگر به عنوان يك پارامتر به تابع داده شدند، يك كپي از آنها به تابع داده ميشود و... دادههايValue - Type در زبان سي شارپ به صورت structure يا enumeration تعريف ميشوند و در بالاترين سطح خود بعد از كلاس Object از كلاس ValueType به ارث ميرسند.
نوع ديگر دادهها در زبان سي شارپ، دادههاي Reference- Type هستند. اين نوع دادهها رفتاري متفاوت با متغيرهايValue - Type دارند.
وقتي يك متغير به صورت Reference-Type تعريف ميشود، خود متغير در حافظه Stack ذخيره ميشود كه خود يك اشارهگر است و اين اشارهگر به خانههاي حافظه Heap اشاره ميكند. اين متغير اگر به عنوان پارامتر به يك تابع داده شود و درون تابع تغييري روي متغير حاصل شود، در بيرون از تابع نيز ديده ميشود. چراكه وقتي به يك تابع داده ميشود، در واقع يك اشارهگر است كه به خانههاي حافظه در Heapاشاره ميكند. داده Reference-Type بايد از نوع class يا Interfaceيا delegate باشند.
اما سوال اصلي در اينجا اين است كه اگر يك متغير Value - Type را بخواهيم به يك تابع بدهيم به طوري كه فراخواني از نوع ارجاع باشد، چه اتفاقي ميافتد؟ آيا زبان سي شارپ اين امكان را به ما ميدهد كه با يك متغير Value - Type رفتاري شبيه نوع دادههاي Reference-Type داشته باشيم؟ در مقالات بعدي به اين سوال جواب داده خواهد شد.
اميربهاءالدين سبطالشيخ
سلام از مطلبی که فرستادی خیلی خوشم اومد و دستت درد نکنه موضوع ارجاع به توابع همیشه مساله ساز بوده ولی یه جاهایی حرفتو قبول ندارم.
اول اینکه سیشارپ با انهمه وسعتی که داره اصلا در حد و اندازه های سی پلاس پلاس نیست که چه برسه به سی یا ابجکتیو سی ولی من بحث سی پلاس پلاسشو که خودت پیش کشیدی رو باز میکنم.
ما در اکثر زبان های برنامه نویسی میتونیم یا ادرس یک متغیر (یعنی خود متغیر-همون کال بای ریفرنس) و هم یک کپی از متغیر (کال بای ولیو) رو به عنوان ارگومان ورودی به متد یا تابعی بفرستیم.
حالا توی همین سی پلاس پلاسی رو که کوچک تر از سیشارپ خوندیدش
ما میتونیم بیش از یک خروجی داشته باشیم از یک تابع یا متد میپرسی چطور خب ساده است ما دو تا عدد به یک تابع میفرستیم از نوع صحیح و با امضای کال بای ولیو
بعد دوتا متغیر دیگه از نوع اعشاری ولی با ارجاع یعنی اینکه ادرسشو میفرستیم به تابع حالا این متغیر های سری دوم میتونند ارایه یا هر شی دیگه ایی هم باشند.حالا در بدنه تابع ما میایم دو متغیر رو یه بار از هم کم میکنیم (دوتا متغیر سری اول از نوع صحیح و با ارجاع کال بای ولیو) و و درجش میکنیم توی متغیر محتوای متغیر اول از سری دوم و یک بار هم با هم جمع میکنم دوتا متغیر اولو و میریزم داخل متغیر دوم از سری دوم.
این کا رو با استفاده از عملگر های * و & انجام میدم.
این نمونه ایی از ارسال بصورت کال بای ریفرنس بود.
دلیلی وجود نداره که چون return یک مقدار رو یفرسته بصورت فراخوانی بازگشتی پشته سیستم برای یک متد دیگه ما نتونیم ارسال چند تایی انجام بدیم مثلا خود همین ریترن میتونه ادرس ابتدای یک ارایه رو به ما برگردونه و ما خودمون روی دیگر عناصر پیمایش بکنیم.
دوم اینکه شما اگه میخوای خروجی تابع 30 بشه که نباید a رو بهلاوه مساوی a+b میکردی ، یا مینوشتی a=a+b یا a+=b یا اینکه با عملگر & ادرس متغیر هاتو به تابع میفرستادی و با عملگر * با محتوای اونا کار میکردی.
کال بای ولیو و کال بای ریفرنس همیشه سوال کنکور و امتحان بوده و هست و اینکه به طور پیش فرض چه زبانی چه نوع ارجاعی رو دیفالت قرار داده که نشان ضعف اون زبان نیست
اگه مانیتونیم با سی پلاس پلاس کاری رو که به سادگی توی سیشارپ میشه انجام داد رو انجام بدیم از ضعف سی پلاس پلاس نیست از بی سوادی و کم تجربگی ماست .اگه همین سیشارپ دات نت نیومد خیلی ها نمیتونستند با خانه سازی بازی کردن ادعای برنامه نویسی بکنند.
اگه سی یا سی پلاس پلاس داره یه عمره جوابگوی تمام نیاز ها میشه و کامپایلر های قدرتمند و استانداردی رو داره به خاطر سادگی و صریح بودن دستوراتشه
کل ویژوال سیشارپ دات نت به اندازه یه دستور exit توی سی هم نیست
این صفحه را در گوگل محبوب کنید
[ارسال شده از: پی سی سیتی]
[تعداد بازديد از اين مطلب: 847]