درود
عزیزان به جز اینکه آبجکت در زمان کامپایل نوع داده مشخص میشه و داینامیک در زمان ران تایم. چه تفاوت های دیگری دارند؟
Printable View
درود
عزیزان به جز اینکه آبجکت در زمان کامپایل نوع داده مشخص میشه و داینامیک در زمان ران تایم. چه تفاوت های دیگری دارند؟
اولی زمان ران تایم و دومی کامپایل.کد:
dynamic i = "10";
int a = Convert.ToInt16(i);
Console.WriteLine(a.GetType());
object j = "10";
int b = Convert.ToInt16(j);
Console.WriteLine(b.GetType());
خیلی شبیه به هم هستند
سلام
سوال جالبی میتواند باشد!
در جهت تکمیل توضیح کوتاه دوستمان iranch میتوانم اضافه کنم...
شباهت فوق العاده:
هردو نوع از نظر پایه ذخیره سازی یکسان هستند در واقع در CLR متغییری به نام dynamic وجود ندارد، (شاهد آنکه دستور typeof یا توابع توسعه یافته روی این نوع و تنها این نوع کار نمیکند!) dynamic در واقع و دقیقاً همان object است.
وقتی متغییری از جنس dynamic تعریف میکنید در واقع متغییری از جنس object تعریف کرده اید.
تفاوت در نحوه رفتار کامپایلر #C با عملیات های روی dynamic است.
برای تصور بهتر از رفتار کمکی کامپایلر ارجاعتان میدهم به عبارات Lambda (که همانطور که میدانید فقط نوعی خلاصه نویسی برای توابع عادی هستند و کامپایلر بجای ما تابع را بصورت عادی در فضای کلاس تولید میکند و کار تایپ ما را کاهش میدهد)
همین وضعیت کاهش کد نویس و تولید کد خودکار توسط کامپایلر برای متغییر های dynamic هم رخ میدهد.
بااجازتان الآن دیروقت است... تفاوت این دو را در فردا یا تعطیلی پس فردا تایپ میکنم و با مثال هایی توضیح میدهم.
شب خوش.
من یکی پیدا کردم.
اولین تفاوت و چرا؟
مورد دوم 10 رو می چسبونه به "10" اما مورد اول خیر.
و جالب اینجاست که تابع GetType اگر روی هر دو اعمال کنیم . میگه String هست.
کد:
object obj = "10";
obj = obj + 10;
Console.WriteLine(obj);
dynamic dyn = "10";
dyn = dyn + 10;
Console.WriteLine(dyn);
سلام مجدد
میبخشید زودتر نتوانستم، متاسفانه این چند روز کمی گرفتار هستم...
هر عملیاتی که روی نوع dynamic انجام شود توسط کامپایلر با نوعی از دستورات reflection انجام میشود، در واقع شما میتوانید هر متد و خصیصه و عملیاتی را روی dynamic نوشته و با موفقیت کامپایل کنید، اگر چیز غیر ممکنی نوشته باشید در زمان اجرا خطا دریافت خواهید کرد.
مورد اول:
فراموش نکنید در CLR نوع dynamic معنی ندارد و وجود ندارد.
متغییر dynamic همان متغییر object است یعنی واقعاً object است فقط وجود این کلمه جدید تفاوت رفتار کامپایلر را سبب میشود پس موارد زیر غیر مجاز هستند:
مورد دوم:کد:Type x = typeof(dynamic);
... static Func1(this dynamic y, ...
void Func2(object z)...
void Func2(dynamic z)...
دقت کنید که هر خصیصه ای روی dynamic صحیح کامپایل میشود ولی یافتن آن خصیصه در زمان اجرا و بر اساس پایه متنی کشف و اجرا میشود، این عملیات بسیار کندتر ولی انعطاف پذیری بالایی دارد.
مورد سوم:کد:public class Class1
{
public int Length;
}
object a = "Ali";
object b = new Class1();
object c = 123;
//خطا نگارشی و عدم کامپایل
int al = a.Length;
//خطا نگارشی و عدم کامپایل
int bl = b.Length;
//خطا نگارشی و عدم کامپایل
int cl = c.Length;
==============
dynamic x = "Ali";
dynamic y = new Class1();
dynamic z = 123;
//کامپایل صحیح و اجرای صحیح
int xl = x.Length;
//کامپایل صحیح و اجرای صحیح
int yl = y.Length;
//کامپایل صحیح و خطا در زمان اجرا
int zl = z.Length;
عملیات روی dynamic شامل بازتعریف اپراتورها نیز میباشد.
مورد چهارم:کد:public object Mul1(object a, object b)
{
//خطا نگارشی و عدم کامپایل
return a * b;
}
public dynamic Mul2(dynamic a, dynamic b)
{
return a * b;
}
dynamic ix = 123;
dynamic iy = 456;
dynamic sx = "Ali";
dynamic sy = "Hassan";
//کامپایل صحیح و اجرای صحیح
dynamic iz = Mul2(ix, iy);
//کامپایل صحیح و خطا در زمان اجرا
dynamic sz = Mul2(sx, sy);
حتماً میدانید که کامپایلر #C تبدیلات پرانتزی را به سه گروه متفاوت از دستورات کامپایل میکند Convert/Cast/Box
میبینید که تبدیل پرانتزی روی object کامپایل به یک عملیات unboxing میشود (یا cast) ولی dynamic بدون هیچ نیازی به تبدیل پرانتزی همان عمل را انجام میدهد و تبدیل واضح پرانتزی منجر به کامپایل عملیات convert میشود.
مورد پنجم:کد:int a = 123;
double b = 123.0;
object a2 = a;
object b2 = b;
//خطا نگارشی و عدم کامپایل
int a3 = a2;
//خطا نگارشی و عدم کامپایل
int b3 = b2;
//کامپایل صحیح و اجرای صحیح
int a4 = (int)a2;
//کامپایل صحیح و خطا در زمان اجرا
int b4 = (int)b2;
==============
int x = 123;
double y = 123.0;
dynamic x2 = x;
dynamic y2 = y;
//کامپایل صحیح و اجرای صحیح
int x3 = x2;
//کامپایل صحیح و خطا در زمان اجرا
int y3 = y2;
//کامپایل صحیح و اجرای صحیح
int x4 = (int)x2;
//کامپایل صحیح و اجرای صحیح
int y4 = (int)y2;
بدیهی است به علت ماهیت reflection در نوع dynamic این کدها در موارد وراثتی و پلی مورفیزمی رفتار چندان صحیحی ندارند (حداقل از یک زاویه دید) پس باید در این متغییر ها حواستان به روابط پلی مورفیزمی باشد و نتایج کاملاً متفاوت و بعضاً نامعقول باشد، مانند:
(البته برای این مورد و عواقب آن میشد مثال بسیار جالب تری هم زد ولی فعلاً گمانم همین ساده تر است و برای کسی که بفهمد هشداری کافی است و برای کسی هم که عواقب آن را متوجه نشود که ما نمیتوانیم کل OOP را اینجا یاددهیم:n02:)کد:public class C1
{
public override string ToString() { return "Hello"; }
}
public class C2
{
public new string ToString() { return "Hello"; }
}
object a = new C1();
object b = new C2();
string a1 = a.ToString(); //result is "Hello"
string b1 = b.ToString(); //run base method...
dynamic x = new C1();
dynamic y = new C2();
string x1 = x.ToString(); //result is "Hello"
string y1 = y.ToString(); //result is "Hello"
مورد ششم:
با کمک کلاس هایی مانند ExpandoObject میتوان امکانات مشابه زبان های javascript و ruby و python و... را پیاده سازی کرد.
(حتماً دیده اید، این همان قابلیتی است که MVC در ViewBag از آن استفاده میکند)کد:dynamic x = new System.Dynamic.ExpandoObject();
x.PropertyName = 25;
x.FuncName = new Func<string, int>(s => s.Length);
x.Ali = "OK";
//...
int i1 = x.PropertyName;
int i2 = x.FuncName("Hassan");
string s = x.Ali;
مورد هفتم:
توانایی dynamic در شناسایی خصایص و توابع و... به انواع دات نتی محدود نمیشود و میتوان از ان برای کار با اشیای COM هم استفاده نمود.
و...
و...
و...
برای درک تفاوت کافیست ماهیت reflection در عملیات های dynamic را درک کنید.
=====
فراموش نکنید اگر نیاز داشتید مشکلی ندارد ولی همه اینها پردازش اضافه نیاز دارند و این یعنی افت سرعت و بازدهی نسبت به کدنویسی عادی.
شب خوش.