PDA

View Full Version : آموزش: هزار و یک ایراد در تاپیک هزار و یک نکته در سی شارپ!



mehdi.mousavi
جمعه 20 آذر 1388, 04:23 صبح
سلام.
تقریبا دو سال پیش بود که بخاطر ارسال 5 ایراد در تاپیک مزبور، جریمه شدم و پستهایم (که در همون تاپیک آوردم) توسط ارسال کننده تاپیک حذف شد. حالا قصد دارم تا در مواقع بیکاری و هر وقت حوصله ام اومد، توی این تاپیک، ایرادهای موجود در اون (به اصطلاح) نکته ها رو باز هم مطرح کنم. امیدوارم هر کسی اون تاپیک رو میخونه، اینها رو هم بخونه تا به اشتباه نیفته. از اولین تاپیک شروع می کنم:

ایراد پست شماره 5: (http://barnamenevis.org/forum/showpost.php?p=467567&postcount=5) حاشیه دار کردن کنترل TextBox با یک رنگ دلخواه
در تکه کد نوشته شده، چند ایراد به چشم میخوره. ابتدا اینکه DC گرفته شده توسط Graphics.FromHdc حتما باید پس از اتمام کار، dispose بشه و الا DC گرفته شده به سیستم بر نمیگیرده! ایراد دوم مقدار دهی پارامتر flags به اینصورته: 1 | 0x0020. این مقادر (یعنی DCX Flag ها) باید مثل WM_ (پیامها) ابتدا بصورت enum یا constant تعریف بشن و سپس از این تعاریف در تابع مزبور استفاده کرد. نکته قابل توجه این هستش که پارامتر دوم همین تابع (hrgnClip) نیز از همین مقادیر استفاده می کنه... ایراد آخر، جایی هستش که ReleaseDC فراخوانی شده. در واقع اگر بهر دلیلی GetDCEx حافظه مورد نظر رو برگردونه ولی اجرای برنامه قبل از خط ReleaseDC به ایراد بخوره، حافظه گرفته شده به سیستم برگردونده نمیشه و Memory Leak بوجود میاد. بنابراین باید فراخوانی ReleaseDC حتما در finally block رخ بده.

mehdi.mousavi
جمعه 20 آذر 1388, 04:34 صبح
ایراد پست شماره 6 (http://barnamenevis.org/forum/showpost.php?p=467568&postcount=6): محو شدن تدریجی یک فرم با تغییر دادن خاصیت Opacity
استفاده از Application.DoEvents اونقدر خطرناک هستش که هرگز در هیچ سناریویی توصیه نمیشه. برای اینکه متوجه بشید DoEvents چیکار میکنه، این پست رو بخونید. (http://barnamenevis.org/forum/showpost.php?p=697754&postcount=5) برای اینکه با مشکلاتی که این منود میتونه بوجود بیاره آشنا بشید، این پست رو بخونید. (http://barnamenevis.org/forum/showpost.php?p=697804&postcount=7) روش صحیح، استفاده از یک Timer یا یک UI Thread برای این منظوره.

mehdi.mousavi
جمعه 20 آذر 1388, 11:41 صبح
ایراد پست شماره 9 (http://barnamenevis.org/forum/showpost.php?p=467572&postcount=9): رسم یک چندضلعی توپر روی یک فرم
ابتدا باید توجه داشته باشید که GDI Object هایی که شما مالک اونها هستید رو باید حتما Dispose کنید. بعنوان نمونه، متغیر blackPen که توسط برنامه نویس ایجاد شده، باید توسط برنامه نویس هم به سیستم برگردونده بشه. نکته دوم، نحوه مطلع شدن از رخداد Paint در خود کلاس صادر کننده event هستش. برای مطلع شدن از هر رخدادی در خود کلاس، باید متود متناظر با اون رویداد رو override کنید (اگر قراره کلاسی هم ایجاد کنید که event خاصی رو صادر کنه، best patterns & practices ما رو به نوشتن چنین متودهای virtual ای ترغیب میکنه). بنابراین، جای Form1_Load باید متود OnLoad رو override کنید، جای Form1_FormClosing، OnFormClosing و بهمین شیوه:

protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
using (Pen blackPen = new Pen(Color.Black, 3))
{
Point point1 = new Point(30, 50);
Point point2 = new Point(100, 25);
Point point3 = new Point(200, 5);
Point point4 = new Point(250, 50);
Point point5 = new Point(270, 100);
Point point6 = new Point(250, 250);
Point[] curvePoints = { point1, point2, point3, point4, point5, point6 };

g.DrawPolygon(blackPen, curvePoints);
g.FillPolygon(Brushes.Red, curvePoints);
}

base.OnPaint(e);
}

mehdi.mousavi
یک شنبه 22 آذر 1388, 01:19 صبح
ایراد پست شماره 185: (http://barnamenevis.org/forum/showpost.php?p=479333&postcount=185)سوییچ کردن بین حالتهای مختلف یک ListView

برای سادگی، کد ذکر شده در اون تاپیک رو اینجا میارم:


private void button2_Click(object sender, EventArgs e)
{
int n = (int) listView1.View;
if (n == 4)
n = -1;
listView1.View = (View)Enum.ToObject(typeof(View), ++n);
}

در خط آخر از این کد، به نحوه تبدیل عدد n به View دقت کنید. جای همچین کدی تنها کافی هستش تا value مورد نظر رو به Enum دلخواه، Cast کنیم:

this.listView1.View = (View)(++n);

همونطور که می بینید، دیگه نیازی به Invoke کردن متود ToObject نیست! در نهایت، کد فوق رو میشد اینطور نوشت:

private void button2_Click(object sender, EventArgs e)
{
if (this.listView1.View + 1 > View.Tile)
this.listView1.View = View.LargeIcon;
else
this.listView1.View++;
}

که دیگه هیچ نیازی به Cast کردن هم نباشه!

mehdi.mousavi
دوشنبه 23 آذر 1388, 00:21 صبح
ایراد پست شماره 164: (http://barnamenevis.org/forum/showpost.php?p=478998&postcount=164) بدست آوردن حروف تشکیل دهنده ی یک رشته
در واقع این پست بنظر میرسه که ایرادی نداره، اما در انتهای اون این جمله آورده شده: "البته روش اول بهینه تر است". در واقع نویسنده استفاده از foreach رو به for بهینه تر دونسته که با توجه به Sample ای که نوشتن، این اصلا صدق نمیکنه! به کدی نوشته شده در این پست دقت کنید:

string testStr = "Sinpin";
for (int counter = 0; counter < testStr.Length; counter++)
MessageBox.Show(testStr[counter].ToString());

string testStr = "Sinpin";
foreach (char c in testStr)
MessageBox.Show(c.ToString());

من این کد رو ساده کردم:

کد اول

string testStr = "Sinpin";

char s;
for (int counter = 0; counter < testStr.Length; counter++)
{
s = testStr[counter];
}

و همینطور:

کد دوم

string testStr = "Sinpin";

char s;
foreach (char ch in testStr)
{
s = ch;
}



اگر به کد IL تولید شده نگاهی بندازید، متوجه میشید که instruction های کد اول، کمتر از کد دوم هستش. من کد اول و دوم رو از نظر Performance تست کردم و به نتایج جالبی رسیدم. کد اول، یعنی استفاده از for بمراتب سریعتر از کد دوم، یعنی foreach هستش. در نتیجه این حرف که "استفاده از foreach بهینه تر هستش" نادرسته و کاملا برعکسه! در واقع، بستگی به شرایط داره... در این مثال، یعنی extract کردن حروف یک string، استفاده از for بمراتب سریعتر از foreach هستش.

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

سایت اول (http://blogs.msdn.com/kevin_ransom/archive/2004/04/19/116072.aspx)
سایت دوم (http://community.sgdotnet.org/blogs/triplez/archive/2005/06/07/17099.aspx)

mehdi.mousavi
دوشنبه 23 آذر 1388, 00:50 صبح
ایراد پست شماره 301 (http://barnamenevis.org/forum/showpost.php?p=550638&postcount=301) و بسیاری از کدهای آورده شده در این تاپیک

کد آورده شده در این پست، ایراد زیاد داره. اما خطرناکترین ایرادی که من هر از گاهی در کد دیگران میبینم، گرفتن کلیه Exception ها توسط catch(Exception ...) هستش.

اگر با C++ در محیط Native کار کرده باشید، با SEH یا Structured Exception Handling باید آشنا باشید. (اگر آشنا نیستید، حتما مقاله Matt Pietrek در مجله MSDN رو بخونید (http://www.microsoft.com/msj/0197/Exception/Exception.aspx). مقاله مال 13 سال پیش هستش، اما خوندنش رو به همه توصیه می کنم. البته اونموقع اسم مجله Microsoft Systems Journal بود، نه MSDN Magazine!).

در محیط .NET، شما نه تنها Exception های تولید شده در Thread های CLR خودتون رو میگیرید، بلکه، این امکان وجود داره که Exception های تولید شده توسط "ایرادی که باعث بوجود اومدن Exception در پردازنده شده" رو هم بگیرید. فرض کنید کد شما باعث بشه تا خطای "Access Violation" رخ بده. این خطا، توسط Kernel، بصورت یک SEH به دست برنامه شما میرسه. چون عبارت catch ای که شما نوشتید، یعنی، catch(Exception ...)، هیچ اطلاعی از این مساله نداره، در نتیجه Exception های SEH رو هم میگیره! و این یعنی افتضاح پشت افتضاح.

کد شما باعث بوجود اومدن خطای Access Violation شده (فرضا با نوشتن در حافظه ای که اجازه نوشتن در اون حافظه رو نداشته) و این Exception تولید شده و برنامه شما اونو گرفته. شما در catch، میرید کاری رو انجام بدید و به خیال خودتون، خطای بوجو اومده رو بازیابی کنید، یا سعی کنید ایراد رو Log کنید و ... (هر کاری! اهمیتی نداره که چی باشه). چون الان حافظه بهم ریخته، هر کاری، تکرار میکنم، هر کاری (منظورم دستورالعمل هستش)، میتونه اوضوع رو پیچیده کنه و باعث از دست رفتن (حتی) داده های Persisted شما بشه.

این مساله رو بخوبی Andrew Pardoe در مقاله خودش (http://msdn.microsoft.com/en-us/magazine/dd419661.aspx) (باز هم) در مجله MSDN توضیح داده. اگر با .NET و تحت این Framework کار میکنید، مطمئن بشید که این مقاله رو می خونید...

در هر حال، این مشکل قراره در .NET 4 رفع بشه، به این ترتیب که Exception های SEH بدست برنامه شما فقط در صورتی برسه که شما تابع خودتون رو با یک Attribute خاص، Decorate کنید. توضیحات بیشتر در مقاله فوق آورده شده.

نتیجه: هرگز از catch(Exception ...) استفاده نکنید!

mehdi.mousavi
دوشنبه 23 آذر 1388, 21:44 عصر
ایراد پست شماره 264: (http://barnamenevis.org/forum/showpost.php?p=493810&postcount=264) طریقه استفاده از کامپوننت timer
این کد اینقدر شرم آوره که ... هر چی فکر کردم متوجه نشدم که فراخوانی Handler مربوط به tick بصورت دستی، چرا انجام شده! تنها چیزی که به ذهنم میاد اینه که احتمالا برنامه نویس (؟) مزبور میخواسته Timer رو بلافاصله پس از Start کردن اون، مجبور به Expire شدن کنه... برای اینکار هم باید یک تابع جدید بنویسید، و اون تابع رو هم هنگام expire شدن timer فراخوانی کنید، هم اگر میخواهید اول کار یک بار اجرا بشه، اونجا هم Call اش کنید.

mehdi.mousavi
دوشنبه 23 آذر 1388, 21:55 عصر
ایراد پست شماره 241: (http://barnamenevis.org/forum/showpost.php?p=484922&postcount=241) فراخوانی یک رویداد از رویداد دیگر
این هم به ایراد قبلی برمیگرده، اما خوب، اوضاعش وخیم تر از قبلی هست:

private void Form1_Load(object sender, EventArgs e)
{
}

private void button1_Click(object sender, EventArgs e)
{
System.EventArgs arg = new System.EventArgs();
Form1_Load(button1.Text, arg);
}


Load Event، رخدادی هستش که هنگام Load شدن فرم مورد نظر (از یک فرآیند)، Fire میشه. این کار اونقدر بیمعنی و گمراه کننده هستش که هرگز نباید انجام بشه. در واقع، نوشتن چنین کدهایی، در نهایت منجر به spaghetti code میشه...

ایراد دوم این کد هم، new کردن یک EventArgs برای ارسال به متود Form1_Load هستش. برای اینکار، شما میتونید از EventArgs.Empty استفاده کنید، جای اینکه یک EventArgs رو new کنید.

mehdi.mousavi
دوشنبه 23 آذر 1388, 22:08 عصر
ایراد پست شماره 224: (http://barnamenevis.org/forum/showpost.php?p=482919&postcount=224)فقط یک نمونه از برنامه بتواند اجرا شود (با استفاده از WMI)

چرا WMI؟ هیچ دلیلی برای استفاده از WMI وجود نداره. درسته، خیلی چیزها شدنیه، اما به چه قیمتی؟ روش صحیح، استفاده از Mutex هستش. (http://www.ai.uga.edu/mc/SingleInstance.html)

mehdi.mousavi
دوشنبه 23 آذر 1388, 23:33 عصر
ایراد پست شماره 131: (http://barnamenevis.org/forum/showpost.php?p=473977&postcount=131) Hash کردن یک رشته متنی با الگوریتم MD5

بر اساس Security Development Lifecycle، کدهاییکه امروزه نوشته میشن دیگه نباید :


از MD4، MD5، SHA1، DES و RC4 (بسته به شرایط)، استفاده کنن
از symmetric key کمتر از 128 بیت استفاده کنن
از RSA key هایی با طول کمتر از 1024 بیت استفاده کنن
و ...

برای اطلاع از کلیه موارد، لطفا به SDL مراجعه کنید.

mehdi.mousavi
سه شنبه 24 آذر 1388, 15:25 عصر
ایراد پست شماره 316: (http://barnamenevis.org/forum/showpost.php?p=588350&postcount=316) تولید رشته های تصادفی بصورت کاملا دستی

SDL شما رو ملزم به تولید اعداد تصادفی توسط کلاس System.Security.Cryptography..::.RNGCryptoServiceP rovider میکنه. هر روش دیگه ای، مردوده. اما اگر این مساله رو نادیده بگیریم، بازهم این کد ایراد داره. به این بخش از کد توجه کنید:

string str = "";
foreach (int j in a)
str += (char)(j);


اینکار صحیح نیست. شما باید از یک StringBuilder برای Concatenate کردن تک تک Char ها استفاده کنید. از نظر کارایی، StringBuilder بسیار بهتر عمل میکنه.

مشکل دوم در این کد، این هستش که Precondition های فراخوانی این تابع در ذهن برنامه نویس بوده. به این بخش از کد توجه کنید:


public string txt_Generator(int size)
{
int[] a = new int[size];


این کد ایراد داره. از کجا معلوم که پارامتر size، هنگام فراخوانی تابع عددی منفی نباشه؟ اگر برنامه نویس فرض رو بر این میگیره که نباید عددی منفی به این تابع پاس بشه، باید این فرض رو حتما در کد قید کنه. تا اگر کسی هم به اشتباه اینکارو کرد، بلافاصله از این مساله مطلع بشه (منظورم در آزمایشگاه هستش)! در واقع، درستش این بود که این کد اینطور نوشته میشد:


private byte[] GenerateRandomString(int size)
{
Debug.Assert(size >= 0);

byte[] data = new byte[size];
RandomNumberGenerator rng = RNGCryptoServiceProvider.Create();
rng.GetNonZeroBytes(data);
return data;
}


این کد، یک Byte array بطول size به شما برمیگردونه. حالا با این array هر کاری خواستید میتونید انجام بدید.

اَرژنگ
چهارشنبه 09 دی 1388, 07:17 صبح
ایراد پست شماره 224: (http://barnamenevis.org/forum/showpost.php?p=482919&postcount=224)فقط یک نمونه از برنامه بتواند اجرا شود (با استفاده از WMI)

چرا WMI؟ هیچ دلیلی برای استفاده از WMI وجود نداره. درسته، خیلی چیزها شدنیه، اما به چه قیمتی؟ روش صحیح، استفاده از Mutex هستش. (http://www.ai.uga.edu/mc/SingleInstance.html)

روش صحیح یکمقداری از سطح بالاتر باید ایجاد بشه،
مشکل اصلی این است که کنترل ایجاد شدن برنامه در دست سیستم عامل است، روش درست به دست گرفتن کنترن از سیستم عامل است، منتها مقدار پیچیدگی و اضافه‌کاری که ایجاد میشه این سوال را پیش میاره که روش صحیح به چه قیمت؟ در حالت فلسفی برنامه همینطوری ایجاد نمیشه، درخاست ایجاد شدنش به دست یک سرویس بررسی میشه و بنابر هر منطقی یا یک نمونه جدید ایجاد میشه و یا نه . همین روش ِرا میشه برایه اینکه یک برنامه بیشتر از یک بار در کل یک سازمان ایجاد نشد و یا مرکزی کردن کنترل ایجاد کردن برنامه میشه استفاده کرد.
روش Mutex را من ۱۵سال پیش استفاده میکردم ولی از یک لحاضی مانند استفاده از متغییر سراسری میماند و برایه همین ازش زیاد خوشم نمیاد (ولی از لحاض کاربردی هیچ اشکالی ندارد).

mehdi.mousavi
چهارشنبه 09 دی 1388, 15:11 عصر
روش صحیح یکمقداری از سطح بالاتر باید ایجاد بشه، مشکل اصلی این است که کنترل ایجاد شدن برنامه در دست سیستم عامل است، روش درست به دست گرفتن کنترن از سیستم عامل است، منتها مقدار پیچیدگی و اضافه‌کاری که ایجاد میشه این سوال را پیش میاره که روش صحیح به چه قیمت؟ در حالت فلسفی برنامه همینطوری ایجاد نمیشه، درخاست ایجاد شدنش به دست یک سرویس بررسی میشه و بنابر هر منطقی یا یک نمونه جدید ایجاد میشه و یا نه . همین روش ِرا میشه برایه اینکه یک برنامه بیشتر از یک بار در کل یک سازمان ایجاد نشد و یا مرکزی کردن کنترل ایجاد کردن برنامه میشه استفاده کرد. روش Mutex را من ۱۵سال پیش استفاده میکردم ولی از یک لحاضی مانند استفاده از متغییر سراسری میماند و برایه همین ازش زیاد خوشم نمیاد (ولی از لحاض کاربردی هیچ اشکالی ندارد).

سلام.
ببینید. این مساله (اگر بخوام سخت گیرانه نگاه کنم) کاملا به حوزه ای بر میگرده که داریم در موردش صحبت می کنیم. بعنوان مثال، در برنامه های Office، چه ضرورتی هستش که یک لایه خارجی کنترل Policy مزبور رو بدست بگیره؟ اگر قراره Word فقط یکبار اجرا بشه و بخشی از یک Enterprise Solution هم نباشه، چرا باید لایه دیگه ای سیاست باز و بسته شدن برنامه رو کنترل کنه؟ شاید منظورتون Fault Tolerant کردن اجرای برنامه و ... باشه. نمیدونم! شاید هم منظورتون لاگین کردن یک ID/PWD مشخص، فقط برای یکبار به سیستم باشه (که خوب، این دیگه ربطی به Instance پیدا نمیکنه)... نمیدونم!

اما مقایسه Mutex با یک متغیر سراسری (قاعدتا در C/CPP)، یه خرده دور از ذهنه. درسته که Handle به هر دو بصورت Global در دسترسه و یکی در User-Mode مدیریت میشه و دیگری در Kernel-Mode، اما بنظرم مقایسه این دو با هم کار شایسته ای نیست.

در هر حال، بعضی چیزها تاریخ مصرف نداره، یا تاریخ مصرف بالایی داره. منم 18 سال پیش از int استفاده میکردم، هنوزم اینکارو میکنم. بستگی داره که کی و کجا بهش نیاز داشته باشم. :چشمک:

موفق باشید.

اَرژنگ
چهارشنبه 09 دی 1388, 16:39 عصر
سلام.
ببینید. این مساله (اگر بخوام سخت گیرانه نگاه کنم) کاملا به حوزه ای بر میگرده که داریم در موردش صحبت می کنیم. بعنوان مثال، در برنامه های Office، چه ضرورتی هستش که یک لایه خارجی کنترل Policy مزبور رو بدست بگیره؟ اگر قراره Word فقط یکبار اجرا بشه و بخشی از یک Enterprise Solution هم نباشه، چرا باید لایه دیگه ای سیاست باز و بسته شدن برنامه رو کنترل کنه؟ شاید منظورتون Fault Tolerant کردن اجرای برنامه و ... باشه. نمیدونم! شاید هم منظورتون لاگین کردن یک ID/PWD مشخص، فقط برای یکبار به سیستم باشه (که خوب، این دیگه ربطی به Instance پیدا نمیکنه)... نمیدونم!

اما مقایسه Mutex با یک متغیر سراسری (قاعدتا در C/CPP)، یه خرده دور از ذهنه. درسته که Handle به هر دو بصورت Global در دسترسه و یکی در User-Mode مدیریت میشه و دیگری در Kernel-Mode، اما بنظرم مقایسه این دو با هم کار شایسته ای نیست.

در هر حال، بعضی چیزها تاریخ مصرف نداره، یا تاریخ مصرف بالایی داره. منم 18 سال پیش از int استفاده میکردم، هنوزم اینکارو میکنم. بستگی داره که کی و کجا بهش نیاز داشته باشم. :چشمک:

موفق باشید.
بله کاملا با نظرتان در مورد اینکه در چه حوزه‌ای کار میکنیم موافقم.
دلیل اینکه استفاده از میوتکس را با متغییر سراسری مقایسه کردم به همان اینکه محدوده حوزه کاری را به چی تعریف کنیم برمیگرده.
همانطوی که گفتم روش میوتکس برایه محدوده اصلی سوال جواب درستی است ولی همانطوری که ما در ریاضیات مدوام محدوده‌ها را برایه حل یک سوال گسترش میدیم )اول از اعداد صحیح به اعداد منفی، کسری، اصم، ..(
در برنامه نویسی هم محدوده را باید سعی کنیم گسترش بدیم ، مثلاً در ریاضی جواب ریشه سوم ۱ ، سه تا عدد هست، جواب اینکه ریشه سوم ۱ ، ۱ است را هم در بر میگیره.
با گسترش دادن حوزه سوال ،جوابی که بدست میاد، جوابه سوال حوزه قبلی را هم در برمیگیره.
در جواب اینکه چرا یک لایه دیگر اضافه بشه )وقتی که ضروری نیست(، این است که دانستن وجود داشتن این قابلیت حتی ایده‌هایی بیشتری در دست برنامه‌نویس قرار میدن.
اینکه استفاده از میوتکس را با استفاده از متغییر سراسری مقایسه میکنم این است که حوزه وجود میوتکس از حوزه‌ای که تعریف و مقدار داده شده خارج است )از یک لحاظ مانند متغییر سراسری(.

حوزه تعریف و امتحان وجود داشتن یک شئی جوانب فلسفی و منطقی هم دارد )برایه مثال، وجود داشتن مثلثهایی که جمع زاویه‌هاشان از ۱۸۰ درجه میتواند بیشتر و یا کمتر باشد به ذهن کمتر کسی میرسه ، در حالتی که میشه بر زمین یک مثلث که جمع زوایاش ۲۷۰ درجه باشد کشید(.

vcldeveloper
یک شنبه 13 دی 1388, 17:16 عصر
درباره مقایسه WMI با Mutex به Performance Hit آن هم توجه کنید! WMI به شدت وابسته به COM هست، و برای استفاده از آن باید اشیاء COM مختلفی در پشت صحنه لود بشند. از طرف دیگه، روش جستجوی مربوطه (حرکت در لیست Processهای در حال اجرا) هم بهینه نیست. روش استفاده شده هم ایمن نیست، چون هیچ تضمینی وجود نداره که در زمان جستجو در لیست Processها، Process مورد نظر ما شروع نشه! بخصوص اگر قرار باشه با این کار بخوایم Processهای در حال اجرا در یک سیستم دیگه را ب WMI چک کنیم. نکته آخر هم اینکه داده های اضافی که این وسط رد و بدل میشه برای کاری که باید انجام بشه خیلی زیاد هست.
بطور خلاصه، WMI برای همچین کاری در مقایسه با Mutex از نظر Performance و قابلیت اطمینان پذیری افتضاح هست!

mehdi.mousavi
پنج شنبه 27 اسفند 1388, 12:32 عصر
ایراد پست شماره 406 (http://barnamenevis.biz/forum/showpost.php?p=930986&postcount=406): نحوه Restart کردن سیستم.
فراخوانی فایل shutdown.exe و ارسال پارامترهای مورد نیاز این Command Utility، روش صحیحی برای Restart کردن سیستم نیست. اگر قرار باشه لیست فایلهای موجود در یک Folder رو بگیرید، آیا خروجی دستور dir رو capture خواهید کرد، یا از Directory.GetFiles استفاده می کنید؟

روش صحیح انجام اینکار، استفاده از ExitWindowsEx Win32 API هستش. ابتدا این تابع رو بدین شکل در برنامه تعریف کنید:


[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
[return: System.Runtime.InteropServices.MarshalAs(System.Ru ntime.InteropServices.UnmanagedType.Bool)]
static extern bool ExitWindowsEx(uint uFlags, uint dwReason);


سپس برای Logoff، Reboot، Shutdown و ... می تونید این تابع رو با پارامترهای مناسب فراخوانی کنید. بعنوان مثال، برای Logoff کردن، می تونید به این شکل عمل کنید:

ExitWindowsEx(0/*Logoff*/, 0 /*Minor/Major Other*/);


به دو نکته دقت کنید:



توی Production Code حتما باید مقادیر uFlags و dwReason رو بصورت enum یا const int از پیش تعریف کنید و من کد فوق رو فقط برای سهولت بدین شکل نوشتم. لیست مقادیر معتبر برای این دو پارامتر رو می تونید اینجا ببینید (http://msdn.microsoft.com/en-us/library/aa376868%28VS.85%29.aspx).
توی ویندوز NT، XP و 2000، قبل از فراخوانی تابع فوق، حتما باید با استفاده از AdjustTokenPrivileges، دسترسی SE_SHUTDOWN_NAME رو به Calling Process بدید، در غیر اینصورت، تابع ExitWindowsEx فالس برمیگردونه و کاری انجام نخواهد داد.

موفق باشید.

mehdi.mousavi
پنج شنبه 27 اسفند 1388, 12:59 عصر
ایراد پست شماره 384 (http://barnamenevis.biz/forum/showpost.php?p=883325&postcount=384): پیدا کردن تعداد خطوط یک متن، بروشی خیلی ساده

کد مزبور رو میشد با یک حلقه for خیلی قشنگ تر نوشت تا یک for...each. اما هدفم عنوان کردن این مساله نبود. در واقع میخواستم شما رو با StringReader آشنا کنم:


int totalLines = 0;
using (StringReader reader = new StringReader(inputString))
{
while (reader.ReadLine() != null)
totalLines++;
}


همونطوری که می بینید، اینجا با استفاده از کلاس StringReader متن مورد نظر خط به خط خونده میشه و در نهایت تعداد خطوط بدست میاد (بدون درگیر شدن با جزییات).

گذشته از اینها، با Regular Expression ها میشه کد مزبور رو ساده تر از اینها هم نوشت. کافیه بدنبال الگوی \n توی متن مورد نظر بگردیم تا تعداد Match ها، تعداد خطوط متن ما رو نشون بده. از این ساده تر فکر نمیکنم امکانپذیر باشه. :)


Regex regex = new Regex("\n", RegexOptions.Multiline);
int totalLines = regex.Matches(inputString).Count + 1;


موفق باشید.