CSCIENCE

CSCIENCE

۲۱ مطلب با کلمه‌ی کلیدی «C#» ثبت شده است

انتخاب فونت مناسب، یکی از مسائلیه که در طراحی UI خیلی مهمه. نکته‌ی مهم‌تر اینه که اگر از فونت سفارشی یا فونتی که فقط روی سیستم خودمون داریم، استفاده کنیم، وقتی که برنامه روی سیستم دیگه‌ای بخواد اجرا بشه، در صورتی که سیستم مقصد فونت مورد نظر شمارو نداشته باشه به مشکل می‌خوره. پس باید کاری کرد که فونت هم با برنامه جابجا بشه.

یه راهش اینه که هروقت برنامه رو جای دیگه میبرین به طرف مقابل بگید "لطفا فونت(های) ... را روی سیستم خود نصب نمایید". درسته که روش ساده و کارامدیه اما "کاربر پسند" نیست. کاربر دوست داره فقط رو فایل اجرای برنامه کلیک کنه و برنامه راحت و روون اجرا بشه.

روش دیگه‌ای که می‌خوام توضیح بدم اینه که فونت(های) مورد نیاز داخل یک فولدر کنار برنامه شما قرار می‌گیرن و فقط کافیه برنامه رو هرجا بردین این فولدر هم ببرین به عبارت دیگه توی پکیج برنامتون این فولدرو بذارید و تمام.

توضیحات روش در ادامه‌ی مطلب.

۳ موافقین ۰ مخالفین ۰ ۰۷ شهریور ۹۲ ، ۱۵:۴۷
cscience

افرایش طول عمر با اسارت*!


می‌دانیم که:

متغیرهای محلی که در یک تابع تعریف می‌شوند، با خروج از تابع از بین می‌روند و به عبارتی پایان عمر آن‌ها همزمان با پایان تابع می‌باشد.

 

اکنون باید دانست که:

متغیر محلی یک تابع، در صورتی که در یک Lambda Expression استفاده شود (Capture شود) طول عمرش به اندازه‌ی نمونه‌ی delegate ساخته شده برای آن Expression، افزایش می‌یابد.


public Func<int> GetFunction()
 {
       int x = 0;
       return () => x++;
 }


Func<int> Inc = GetFunction();
Inc();
Inc();
MessageBox.Show(Inc().ToString());     // 2


 

* از بین معانی کلمه‌ی Capture، به نظرم انتخاب جالبی برای عنوان بود :دی

۰ موافقین ۰ مخالفین ۰ ۰۶ شهریور ۹۲ ، ۱۹:۳۴
cscience
دقت یا سرعت؟

باید دانست که
:
در سیشارپ برای نگه‌داری مقادیر اعشاری، نوع داده‌های مختلفی وجود دارند. هدف این پست بررسی دو نوع داده‌ی double و decimal می‌باشد.

  • نوع double: این نوع داده، محاسبات را در مبنای 2 انجام می‌دهد، حدود 14 تا 15 رقم اعشار دقت دارد و بازه‌ی عددی حدود 324-^10 تا حدود 308^10 را در بر می‌گیرد (مثبت و منفی).
  • نوع decimal: این نوع داده، محاسبات را در مبنای 10 انجام می‌دهد، حدود 28 تا 29 رقم اعشار دقت دارد و بازه‌ی عددی حدود 28-^10 تا 28^10 را دربر می‌گیرد (مثبت و منفی).
این نکته از آن جهت اهمیت دارد که:
هنگامی که در محاسبات دقت زیاد لازم است می‌توان از decimal استفاده کرد اما decimal دارای دو محدودیت زیر است:
  • بازه‌ی عددی نسبتا کوچک
  • کاهش سرعت محاسبات (تقریبا 10 برابر کندتر از double)
پس همواره باید بررسی کرد که دقت مهم است یا سرعت. معمولا باید بین این دو معیار توازن برقرار بشه تا یه برنامه‌ی خوبی ساخته بشه.

۰ موافقین ۰ مخالفین ۰ ۰۴ شهریور ۹۲ ، ۰۱:۳۷
cscience
تفاوت out و ref

باید دانست که:
کلمات کلیدی out و ref هر دو برای فراخوانی با ارجاع استفاده می شوند اما دو تفاوت کاربردی در آن ها وجود دارد:
  • هنگامی که از ref استفاده می کنید، قبل از فراخوانی، متغیر مربوطه حتما باید مقدار دهی شده باشد اما در مورد out اینطور نیست.
  • هنگامی که آرگومان out وجود دارد، قبل از اینکه کار تابع تمام شود، حتما باید به آن متغیر یک مقدار نسبت داده شود در غیر این صورت خطای کامپایل خواهید داشت.
این نکته از آن جهت اهمیت دارد که:
هنگامی که می خواهید از یک تابع چند خروجی با تایپ های مختلف بگیرید از out استفاده کنید. اینکار هم خوانایی را افزایش می دهد و هم از اشتباهات ناخواسته جلوگیری می کند.

بهتر است که:
از این روش تنها موقعی استفاده کنید که مجبورید. گرفتن چندین خروجی از یک تابع می تواند پیچیدگی کد را زیاد و رفع خطای آن را سخت تر کند.
۰ موافقین ۰ مخالفین ۰ ۰۴ شهریور ۹۲ ، ۰۱:۳۶
cscience
ارجاع یا مقدار؟

باید دانست که:
هنگامی که شما یک تابع را به صورت عادی صدا می زنید، تمامی آرگومان ها به وسیله ی مقدار فرستاده می شوند یا به عبارت دیگر یک کپی از مقدار آن ها به تابع فرستاده می شود و تغییراتی که توسط تابع روی متغیر انجام می شود در متغیر اصلی تاثیر نمی گذارد. این امر در مورد تایپ های پایه ای سیشارپ کاملا واضح است. اما اگر دقت کرده باشید وقتی یک شئ نمونه از یک کلاس را به عنوان آرگومان ارسال کنید، با تغییر اجزای آن شئ در تابع، این تغییرات در شئ اصلی هم قابل دیدن است. سوال اینجاست که اگر کپی فرستاده شده است پس چرا تغییرات باقی مانده است؟
برای جواب این سوال باید به مفاهیم شئ گرایی مراجعه کرد. هنگامی که شما یک نمونه از یک کلاس ایجاد می کنید، ابتدا در حافظه مکانی برای اطلاعات و اجزای شئ در نظر گرفته می شود و سپس آدرس آن محل در یک متغیر که شما با نام شئ به آن دسترسی دارید، ذخیره می شود. پس چیزی که به عنوان مقدار شناخته می شود، آدرس محل اجزای شئ است. حال وقتی یک شئ را به یک تابع ارسال می کنید این آدرس است که کپی می شود و نه محتویات آدرس. اکنون هر تغییری که در تابع روی شیئی که متغیر مربوطه به آن اشاره می کند، رخ دهد، در همان آدرس ثبت می شود و چون این یک آدرس مشترک است، تغییرات از طریق متغیر اصلی هم قابل دیدن است. دقت کنید که اگر مقدار متغیر یا همان آدرس را در تابع تغییر دهید، هیچ تغییری در مقدار متغیر اصلی ایجاد نمی شود.
حال اگر قصد دارید یک ارجاع واقعی انجام دهید، باید از کلمه کلیدی ref قبل از نام آرگومان مورد نظر (هنگام تعریف و فراخوانی تابع) استفاده کنید.
۰ موافقین ۰ مخالفین ۰ ۰۴ شهریور ۹۲ ، ۰۱:۳۵
cscience
آزادسازی و مدیریت منابع (حافظه)

باید دانست که:
مدیریت فضاهای خالی و یا بلا استفاده حافظه در پروژه های بزرگ مسئله ی مهمی است. خوشبختانه سیشارپ با استفاده از Garbage Collector تا حد خیلی خوبی این عمل را انجام می دهد. به این صورت که به صورت موازی با برنامه ی شما اجرا می شود و هرگاه شئی پیدا کند که ارجاع به آن وجود ندارد و یا مطمئن باشد که دیگر به آن ارجاعی داده نمی شود، حافظه ی آن را آزاد می کند.
اما موازی اجرا شدن خود مسئله ی بزرگیست. این مسئله باعث می شود تا نتوان تشخیص داد چه موقع آزاد سازی صورت می گیرد. گاهی اوقات لازم است در یک زمان مشخص منبع آزاد شود. برای حل این مشکل لازم است از آزاد سازی دستی استفاده کنیم.
راه ساده برای این کار استفاده از Interfaceی به نام IDisposable می باشد. اکنون در کلاس شما باید متد Dispose به صورت مناسب در جهت آزاد سازی منابع مورد نظر پیاده سازی شود.

class MyClass IDisposable
{
        public void Dispose()
        {
            // Clean Up Here
        }
}

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

این نکته از آن جهت اهمیت دارد که:
شاید این سوال را بپرسید که دلیل استفاده از IDisposable چیست و چرا یک متد به همین نام ننویسیم؟ کدی که در اینجا می بینید ظاهر کار است. سیشارپ در عمل از شئ دیگری استفاده می کند که از بوجود آمدن مشکلات احتمالی جلوگیری می کند. یکی از مشکلات Garbage Collector است! فرض کنید دستورات شما برای آزاد سازی منبع به سرعت انجام نشود و کمی طولانی شود و از طرف دیگر Garbage Collector که موازی اجرا شده است برای حذف شئ شما در نیمه ی کار سر می رسد. خودتان تصور کنید که چه مشکلات غیر قابل پیش بینی می تواند رخ دهد. اما با استفاده از IDisposable در هنگام استفاده از Dispose به Garbage Collector اطلاع داده می شود که عمل آزاد سازی صورت گرفته است و لازم نیست برای آزاد سازی این شئ کاری انجام دهد.

نکته دیگر اینکه:
گاهی اوقات زمان آزادسازی (قطعیت) اهمیت ندارد و فقط لازم است در هنگام آزاد سازی چند عمل دیگر انجام شود. به عبارت دیگر وقتی Garbage Collector برای آزاد سازی اقدام می کند، قبل از آن کارهای دیگری نیز انجام شود. برای این کار کافیست از finalizer استفاده کنید.

~MyClass()
{
    // Clean Up Here
    // Or Just Call Dispose()
}


۱ موافقین ۰ مخالفین ۰ ۰۴ شهریور ۹۲ ، ۰۱:۳۵
cscience

دستورات یکسان برای چند case

باید دانست که:
برای اینکه بتوان در ساختار switch یک دستور را برای چند case اجرا کرد، باید مانند نمونه زیر کد نوشت


switch (myint)
            {
                case 1:
                case 2:
                case 3:
                    Console.WriteLine("It's OK");
                    break;
                case 4:
                    Console.WriteLine("It Isn't OK");
                    break;
            }

در مثال بالا، برای حالات 1 و 2 و 3 جمله ی It's OK چاپ می شود و برای حالت 4 جمله ی It Isn't OK.
۰ موافقین ۰ مخالفین ۰ ۰۴ شهریور ۹۲ ، ۰۱:۳۳
cscience
تفاوت عملگر as و (type)

باید دانست که:
برای تبدیل صریح نوع داده ها به یکدیگر دو راه وجود دارد
  • استفاده از عملگر as
  • استفاده از عملگر (Type)
تفاوت مهمی که بین این دو روش وجود دارد این است که در روش اول، اگر تبدیل قابل انجام شدن باشد، نتیجه داده ی تبدیل شده است و اگر تبدیل غیر قابل انجام شدن باشد نتیجه null است. اما در روش دوم اگر تبدیل غیر قابل انجام شدن باشد، یک exception از نوع InvalidCastException ارسال می شود.

نحوه ی استفاده از هر دو روش:

Type1  varname1  =  new Type1([args]);
Type2  varname2  =  (Type2) varname1;

Type1  varname1  =  new Type1([args]);
Type2  varname2  =  varname1  as  (Type2);

۰ موافقین ۱ مخالفین ۰ ۰۴ شهریور ۹۲ ، ۰۱:۳۱
cscience
null پذیری

باید دانست که:

در سیشارپ تایپ ها به دو دسته کلی تقسیم می شوند
  • Value Types: تایپ هایی که مستقیما شامل مقدار هستند، مانند تایپ های پایه ای (intdoublefloatdecimal)
  • Reference Types: تایپ هایی که شامل ارجاع به محلی از حافظه هستند که شامل مقدار مربوطه است مانند کلاس ها
یکی از تفاوت های این دو دسته در امکان null بودن آن ها است. Value Typeها مقدار null را قبول نمی کنند. برای اینکه بتوانیم مقدار null به این دسته از تایپ ها نسبت دهیم (null پذیر کنیم) باید از شئ Nullable استفاده کنیم.

Nullable<int> myint = 10;
myint = null;               //No Error!

در یک پروژه که تعداد null پذیر کردن ها زیاد باشد، نوشتن Nullable باعث کاهش خوانایی کد می شود به همین دلیل syntax دیگری برای این کار وجود دارد. کافیست مقابل اسم تایپ از علامت سوال استفاده کنیم:

int? myint = 10;
myint = null;               //No Error!


این نکته از این جهت اهمیت دارد که:
هنگامی که از پایگاه داده های رابطه ای استفاده می کنید به دلیل اینکه این گونه پایگاه داده ها برای فیلدهای نوع های پایه مثل int هم null پذیر هستند، هنگامی که داده null از آن ها خوانده می شود اگر متغیر شما null پذیر نباشد برنامه ی شما exception ارسال خواهد کرد و در صورت کنترل نکردن آن، اجرای برنامه متوقف می شود.
البته null پذیری در جاهای مختلفی می تواند کاربرد داشته باشد. مثال بالا به دلیل واضح تر بودن آورده شده است.
۰ موافقین ۱ مخالفین ۰ ۰۳ شهریور ۹۲ ، ۰۱:۳۰
cscience
رفتار رشته ها و نحوه ی ساختن یک رشته از اجزای آن

باید دانست که:
رشته ها (string) در سیشارپ از نوع غیر قابل تغییر (immutable) هستند. به این معنا که وقتی یک رشته نسبت داده شد، دیگر نمیتوان محتوای همان خانه از حافظه را با رشته ی جدید تغییر داد و نسبت دهی و یا هرگونه تغییر در رشته ی فعلی، باعث ایجاد رشته ی جدید در خانه ی دیگری از حافظه می شود و در نهایت تنها ارجاع رشته ی قبلی به رشته ی جدید تغییر می یابد.

این نکته از این جهت اهمیت دارد که:
وقتی در حال ساختن یک رشته به صورت پویا هستید (به عنوان مثال می خواهید با استفاده از حلقه تمامی اعضای یک آرایه را در یک رشته جمع آوری کنید) هنگامی که تعداد دفعات تغییر رشته زیاد می شود، بخش زیادی از حافظه برای مدتی توسط رشته های قبلی بلا استفاده می شود (تا هنگامی که garbage collector برسه). سیشارپ برای حل اینگونه مشکلات در رشته ها، شئ دیگری را در اختیارمان قرار داده است. با استفاده از یک StringBuilder ابتدا تمامی اجزا رشته را در این شئ جمع آوری می کنید و سپس متد ToString آن را صدا می زنید.



int[] numbers = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
StringBuilder numbersString = new StringBuilder();
foreach (int in numbers)
{
    numbersString.Append(n);
    numbersString.Append(" - ");
}
string s = numbersString.ToString();


البته لازم نیست هرجا که رشته ای را تغییر می دهید از این روش استفاده کنید. تنها جاهایی استفاده کنید که تعداد تغییرات یک رشته در طول برنامه معلوم می شود و اینکه احتمال می دهید تعداد این تغییرات زیاد خواهد بود. در مثال بالا آرایه را ثابت فرض کردم تا فقط بتوانم نحوه ی استفاده از StringBuilder را نمایش دهم.

راه دیگری که برای حل این مسئله وجود دارد استفاده از امکان Join در LINQ است.
۰ موافقین ۰ مخالفین ۰ ۰۳ شهریور ۹۲ ، ۰۱:۲۶
cscience