PDA

View Full Version : گفتگو: کدهای جالب - شماره 1 - String Interning و Transitivity در C#‎‎



علیرضا مداح
چهارشنبه 22 مهر 1388, 12:46 عصر
سلام دوستان عزیز،
از این پس سلسله مطالبی تحت عنوان "کدهای جالب" در این بخش قرار داده شده و از کاربران خواسته می شود که بر روی آن قطعه کد به بحث و تبادل نظر پردازند، هر نمونه کد هدف خاصی را دنبال می کند که تا انتهای بحث به طور کامل مشخص خواهد شد. در صورتی که در هر نمونه کد از منبع دیگری نیز کمک گرفته شده باشد، در انتهای بحث اعلام خواهد شد،

کدهای جالب - شماره 1 - String Interning و Transitivity در C#‎‎‎‎‎
اگر کمی با ریاضیات آشنا باشید، می دانید که تساوی(Equality) داراری ویژگی هایی است که تعدی(Transitivity) یکی از آنها می باشد،
با این مفهوم آشنا نیستید؟ سادست:

If A=B And B=C Then A=C

آیا به نظر شما این ویژگی در تمامی شرایط و همیشه در C#‎‎‎‎‎ وجود دارد؟
یه نمونه کذ زیر توجه کنید:

using System;
namespace InterestingCodes.No1
{
class Program
{
static void Main(string[] args)
{
object obj = "String";
string str = "String";
string str2 = System.Type.GetType("System.String").Name;
Console.WriteLine("obj == str : {0}", obj == str);
Console.WriteLine("str == str2 : {0}", str == str2);
Console.WriteLine("obj == str2 : {0}", obj == str2);
Console.ReadLine();
}
}
}
نتیجه:


obj == str : True
str == str2 : True
obj == str2 : False
با اجرای کد فوق در می یابید که با اینکه متغیر های obj,str,str2 دارای یک مقدار هستند، اما ویژگی تعدی در آنها صدق نمی کند و برخلاف انتظار، عبارت obj == str2 مقدار false را برمی گرداند،
حال می خواهیم ببینیم این اتفاق چگونه رخ داده است.
در پایان این بخث به نتایج جالبی خواهیم رسید،
پیشاپیش از شرکت دوستان در بخث سپاسگزارم،/

پ.ن: از همفکری آقای کشاورز نیز ممنونم./

Behrouz_Rad
چهارشنبه 22 مهر 1388, 12:58 عصر
خط آخر نتیجه False میشه. اصلاح کن.

majid325
چهارشنبه 22 مهر 1388, 13:10 عصر
توي خط 13 هم چون casting صورت نگرفته ، Rference equals داره صورت ميگيره كه خروجي هم منطقي هست.

Mehdi Asgari
پنج شنبه 23 مهر 1388, 17:57 عصر
تساوی مقادیر و اشیا (Object Equality) در دات نت داستان غم انگیز و طولانی ای داره که می تونید با مراجعه به کتاب CLR Via C# اون رو بخونید. من در اینجا فقط به توضیح همین قطعه کد و دلیل تفاوت خروجی ها بسنده می کنم.
نکتۀ 1 : وقتی دو شی (یا بهتر بگم reference type) با هم مقایسه میشن ، در واقع مقایسه بین reference اون ها صورت می گیره. یعنی اگر هر دو به یک مکان در حافظه اشاره کنند ، اون وقت یکی هستن وگرنه خیر
نکتۀ 2 : با این که رشته هم reference type هست ولی موقع مقایسۀ دو رشته ، رویه فرق می کنه:
ابتدا طول دو رشته با هم مقایسه میشه . اگر مساوی نبودن false برگردونده میشه ، وگرنه احتمال داره مساوی باشن که اون وقت تک تک کاراکتر ها با هم مقایسه میشن
نکتۀ 3: دو نوع مقایسه داریم: structural و referential . در نوع اول (ساختاری) ما به محتوای دو طرف مقایسه شونده کار داریم (یعنی جایی که در اون ذخیره شدن مهم نیست ، مهم اینه که مقدارشون یکی باشه. مثل مقایسۀ دو عدد با همدیگه) و در نوع دوم (ارجاعی) ، به جایی که اشیا در اون ذخیره شدن

رشته هایی که در کد توسط کاربر تعریف میشن (مثل “String” و “System.String” در کد فوق) در متادیتای اسمبلی ذخیره میشن. رشته ها در دات نت immutable یا تغییر ناپذیر هستن (یعنی در کد زیر ، رشتۀ “Hello” از بین نمیره و همچنان در حافظه هست ، منتها شی str دیگه به اون اشاره نمی کنه ، بلکه به جایی که رشتۀ “Yellow” در اون هست اشاره می کنه:


string str = “Hello”;
str = “Yellow”;
خب ، حالا که رشته ها تغییر ناپذیرن (بر خلاف سی پلاس پلاس) پس با ایجاد هر رشتۀ جدید با مقدار “Hello” همه به یک مکان از حافظه اشاره می کنن. خب پس چرا در کد بالا str2==obj درست نیست ؟ دلیل اینه که دو تا reference type با هم دارن مقایسه میشن و این مقایسه از نوع referential هست؛ اما str2 و obj به یک جا اشاره نمی کنن (str2 در متادیتای اسمبلی ما ذخیره نشده و از طریق Reflection اون رو موقع اجرا به دست می یاریم. اما obj و str هر دو به یک مکان از متادیتای برنامه اشاره می کنن)
ویژگی های یک مقایسۀ خوب :
1- باید انعکاسی باشه. یعنی x باید با خودش برابر باشه
2- باید متقارن باشه. یعنی اگر x = y هست ، بالعکسش هم باید صادق باشه
3- باید transitive (گذرا ؟) باشه. یعنی اگر x و y برابر باشن و y و z هم برابر باشن ، آنگاه x و z هم باید برابر باشن

در کد آقای مداح ما ویژگی سومی رو نداریم. حالا اگه بخوایم مقایسۀ سومی هم true برگردونه اون وقت باید از structural equality استفاده کنیم. چطوری ؟
obj رو cast می کنیم به string. یعنی:


Console.WriteLine("obj == str2: {0}",(string)obj==str2);

علیرضا مداح
شنبه 25 مهر 1388, 17:28 عصر
ممنونم آقای عسگری؛ در تصریح گفته های شما و جهت ادامه بحث نکاتی را مطرح می کنم:


نکتۀ 1 : وقتی دو شی (یا بهتر بگم reference type) با هم مقایسه میشن ، در واقع مقایسه بین reference اون ها صورت می گیره. یعنی اگر هر دو به یک مکان در حافظه اشاره کنند ، اون وقت یکی هستن وگرنه خیر


در دات نت اشیائی که از نوع object هستند، در هنگام مقایسه، رفرنس آن ها با یکدیگر مقایسه می گردد که اینکار از طریق متد System.Object.ReferenceEquals(obj1,obj2) صورت می گیرد،


نکتۀ 3: دو نوع مقایسه داریم: structural و referential

یا به عبارتی Reference-Comparison و Value-Comparison،
در C#‎ برای هر دو نوع مقایسه می توان از اپراتور == استفاده نمود، پس این اپراتور بسته به اشیائی که با یکدیگر مقایسه می شوند یکی از دو مقایسه ذکر شده را انجام می دهد،

خوب در کدی که قرار داده شد، در حقیقت این دو مقایسه در حال ترکیب شدن با هم هستند و اگر دقت کنید در خطوط 11 و 13 که یک شیء از نوع object در حال مقایسه با شیء دیگری از نوع string است با Warning زیر روبرو می شوید:

Possible unintended reference comparison; to get a value comparison, cast the left hand side to type 'string'.

پس دقت کنید که اپراتور == می تواند عملکردی متفاوت با آنچه در ذهن شماست داشته باشد،

حالا به یک قضیه ی مهم میرسیم،
به نظر شما چرا مقایسه های اول و سوم مثل یکدیگر عمل نمی کنند؟

،/

Javad_raouf
شنبه 03 مهر 1389, 14:18 عصر
سلام
خیلی جالب بود
ولی چرا این تاپیک داره خاک می خوره
لطفا کس دیگری اگر از این جور کد ها داره بزاره
با تشکر

r00tkit
شنبه 03 مهر 1389, 19:28 عصر
دوست من یه سر به وبلاگ Eric Lippert (http://blogs.msdn.com/b/ericlippert/)بزن

حتی همین مثال بالا هم تو وبلاگ هستش (http://blogs.msdn.com/b/ericlippert/archive/2009/09/28/string-interning-and-string-empty.aspx)

علیرضا مداح
شنبه 03 مهر 1389, 20:16 عصر
سلام،
ذوست من، بنده همیشه به وبلاگ این انسان بزرگ سر می زنم و یکی از الگوهای بنده و دیگر دوستان علاقه مند به علم هستند، ایده ی قرار دادن این مطلب در اینجا هم از وبلاگ ایشان نشات گرفته شده بود، در پست اول هم ذکر کرده بودم که در انتهای بحث، منابع را ذکر خواهم کرد، اما به دلیل استفبال نه چندان خوب دوستان از اینگونه بحث ها (به جز جناب مهدی عسگری که همین جا تشکر ویژه ای از ایشان دارم)، این بحث به انتها نرسید،/

Javad_raouf
شنبه 03 مهر 1389, 20:21 عصر
سلام،
ذوست من، بنده همیشه به وبلاگ این انسان بزرگ سر می زنم و یکی از الگوهای بنده و دیگر دوستان علاقه مند به علم هستند، ایده ی قرار دادن این مطلب در اینجا هم از وبلاگ ایشان نشات گرفته شده بود، در پست اول هم ذکر کرده بودم که در انتهای بحث، منابع را ذکر خواهم کرد، اما به دلیل استفبال نه چندان خوب دوستان از اینگونه بحث ها (به جز جناب مهدی عسگری که همین جا تشکر ویژه ای از ایشان دارم)، این بحث به انتها نرسید،/
سلام و تشکر بابت گذاشتن این تاپیک
من به شخصه خیلی لذت بردم ولی شما برای استقبال باید تاپیک را پربار کنید تا استقبال شود با یک پست که نباید توقع استقبال داشت

r00tkit
یک شنبه 04 مهر 1389, 09:51 صبح
سلام

اقای مداح بنده یکی از طرف داران این بحث هستم( تو .net بیشتر مطالعهاتم در مورد inside و internal و depth و... هستش تا مباحث دیگه )

شما شروع دوباره کنید ما هم ادامه می دیم

با تشکر./