يُوفِّر فضاء الاسم System.Diagnostics
العديد من الأصناف بهَدَف التَشخِيص، مثال أصناف للتَعامُل مع عمليات النظام (processes)، وأُخرى تَعمَل كعَدادات لقياس الأداء.
أوامر الصدفة (shell commands)
تنفيذ أوامر الصَّدَفَة
يُستخدَم التابع Process.Start
لتَّنْفيذ أمر صَّدَفَة (shell commands) تَّنْفيذًا برمجيًا. يتم ذلك من خلال إرساله للأمر المُمرَّر إليه إلى برنامج سطر الأوامر cmd.exe
، كالتالي:
using System.Diagnostics; string strCmdText = "/C copy /b Image1.jpg + Archive.rar Image2.jpg"; Process.Start("CMD.exe",strCmdText);
تَتحَكَم الخاصية WindowStyle
بحالة نافذة سطر الأوامر (cmd) عند تَّنْفيذ الأمر، فمثلًا يُمكِن إخفائها كالتالي:
using System.Diagnostics; Process process = new Process(); ProcessStartInfo startInfo = new ProcessStartInfo(); startInfo.WindowStyle = ProcessWindowStyle.Hidden; startInfo.FileName = "cmd.exe"; startInfo.Arguments = "/C copy /b Image1.jpg + Archive.rar Image2.jpg"; process.StartInfo = startInfo; process.Start();
إرسال أوامر إلى سطر الأوامر واستقبال خرجها
يُعيد التابع SendCommand
-المُعرَّف بالمثال التالي- سِلسِلة نصية تتَضمَن مُحتوَى كلًا من مَجْرى الخَرْج القياسي (STDOUT) ومَجْرى الخَطأ القياسي (STDERR) بعد تَّنْفيذ أمر صدَفَة، بالاعتماد على الحَدَثين OutputDataReceived
و ErrorDataReceived
، كالتالي:
private static string SendCommand(string command) { var cmdOut = string.Empty; var startInfo = new ProcessStartInfo("cmd", command) { WorkingDirectory = @"C:\Windows\System32", WindowStyle = ProcessWindowStyle.Hidden, // لإخفاء نافذة سطر الأوامر UseShellExecute = false, // لا تستخدم طرفية نظام التشغيل لبدء العملية CreateNoWindow = true, // ابدأ العملية بنافذة جديدة RedirectStandardOutput = true, // مطلوب لإتاحة مجرى الخرج القياسي RedirectStandardError = true // مطلوب لإتاحة مجرى الخطأ القياسي }; var p = new Process {StartInfo = startInfo}; p.Start(); p.OutputDataReceived += (x, y) => cmdOut += y.Data; p.ErrorDataReceived += (x, y) => cmdOut += y.Data; p.BeginOutputReadLine(); p.BeginErrorReadLine(); p.WaitForExit(); return cmdOut; }
يُمكِن استدعاء التابع بالأعلى كالآتي:
var servername = "SVR-01.domain.co.za"; var currentUsers = SendCommand($"/C QUERY USER /SERVER:{servername}")
يَكُون الخَرْج كالتالي:
string currentUsers = "USERNAME SESSIONNAME ID STATE IDLE TIME LOGON TIME Joe.Bloggs ica-cgp#0 2 Active 24692+13:29 25/07/2016 07:50 Jim.McFlannegan ica-cgp#1 3 Active . 25/07/2016 08:33 Andy.McAnderson ica-cgp#2 4 Active . 25/07/2016 08:54 John.Smith ica-cgp#4 5 Active 14 25/07/2016 08:57 Bob.Bobbington ica-cgp#5 6 Active 24692+13:29 25/07/2016 09:05 Tim.Tom ica-cgp#6 7 Active . 25/07/2016 09:08 Bob.Joges ica-cgp#7 8 Active 24692+13:29 25/07/2016 09:13"
ملحوظة:
سيُعيد التابع المُعرَّف بالأعلى مُحتوَى كلًا من مَجْرى الخَرْج القياسي (STDOUT) ومَجْرى الخٍَطأ القياسي (STDERR) مَضْمومين بسِلسِلة نصية واحدة؛ حيث يُلحِق كلًا من الحَدَثين OutputDataReceived
و ErrorDataReceived
البيانات المُستلَمة إلى نفس المُتَغيّر cmdOut
.
يَقتصِر أحيانًا الولوج إلى الخادم المَعنِّى على مُستخدِمين بعينهم. إذا كان لديك بيانات دخول مُستخدِم مُعين، فمن المُمكن أن تُرسِل اِستعلامات (queries) إلى ذلك الخادم كالتالي:
private static string SendCommand(string command) { var cmdOut = string.Empty; var startInfo = new ProcessStartInfo("cmd", command) { WorkingDirectory = @"C:\Windows\System32", // This does not actually work in conjunction with "runas" - the console window will still appear! WindowStyle = ProcessWindowStyle.Hidden, UseShellExecute = false, CreateNoWindow = true, RedirectStandardOutput = true, RedirectStandardError = true, Verb = "runas", Domain = "doman1.co.za", UserName = "administrator", Password = GetPassword() }; var p = new Process {StartInfo = startInfo}; p.Start(); p.OutputDataReceived += (x, y) => cmdOut += y.Data; p.ErrorDataReceived += (x, y) => cmdOut += y.Data; p.BeginOutputReadLine(); p.BeginErrorReadLine(); p.WaitForExit(); return cmdOut; }
التابع GetPassword
لجلْب كلمة السر:
static SecureString GetPassword() { var plainText = "password123"; var ss = new SecureString(); foreach (char c in plainText) { ss.AppendChar(c); } return ss; }
ضبط الإعداد ProcessThread.ProcessorAffinity
تُعبر الخاصية ProcessorAffinity
من النوع IntPtr
عن المُعالج (processor) الذي يُنفِّذ خيط العملية (process thread). يَعتمِد هذا الإعداد افتراضيًا على عدد مُعالِجات الحاسوب.
اِستخدِم الشيفرة التالية لجَلْب خاصية ProcessorAffinity
لعملية:
public static int GetProcessAffinityMask(string processName = null) { Process myProcess = GetProcessByName(ref processName); int processorAffinity = (int)myProcess.ProcessorAffinity; Console.WriteLine("Process {0} Affinity Mask is : {1}", processName, FormatAffinity(processorAffinity)); return processorAffinity; } public static Process GetProcessByName(ref string processName) { Process myProcess; if (string.IsNullOrEmpty(processName)) { myProcess = Process.GetCurrentProcess(); processName = myProcess.ProcessName; } else { Process[] processList = Process.GetProcessesByName(processName); myProcess = processList[0]; } return myProcess; } private static string FormatAffinity(int affinity) { return Convert.ToString(affinity, 2) .PadLeft(Environment.ProcessorCount, '0'); }
يُستخدَم كالآتي:
private static void Main(string[] args) { GetProcessAffinityMask(); Console.ReadKey(); }
الخَرْج:
// Output: // Process Test.vshost Affinity Mask is : 11111111
اِستخدِم الشيفرة التالية لضبط خاصية ProcessorAffinity
لعملية:
public static void SetProcessAffinityMask(int affinity, string processName = null) { { Process myProcess = GetProcessByName(ref processName); Console.WriteLine("Process {0} Old Affinity Mask is : {1}", processName, FormatAffinity((int)myProcess.ProcessorAffinity)); myProcess.ProcessorAffinity = new IntPtr(affinity); Console.WriteLine("Process {0} New Affinity Mask is : {1}", processName, FormatAffinity((int)myProcess.ProcessorAffinity)); }
يُستخدَم كالآتي:
private static void Main(string[] args) { int newAffinity = Convert.ToInt32("10101010", 2); SetProcessAffinityMask(newAffinity); Console.ReadKey(); }
الخَرْج:
// Output : // Process Test.vshost Old Affinity Mask is : 11111111 // Process Test.vshost New Affinity Mask is : 10101010
قياس الأداء باستخدام النوع Stopwatch
يُمكِن اِستخدَام النوع Stopwatch
بفضاء الاسم System.Diagnostics
لقياس أداء (benchmark) كُتلة من الشيفرة، كالتالي:
using System; using System.Diagnostics; public class Benchmark : IDisposable { private Stopwatch sw; public Benchmark() { sw = Stopwatch.StartNew(); } public void Dispose() { sw.Stop(); Console.WriteLine(sw.Elapsed); } } public class Program { public static void Main() { using (var bench = new Benchmark()) { Console.WriteLine("Hello World"); } } }
مواصفات اصطلاحية للشيفرة (code contracts)
يُوفِّر فضاء الاسم System.Diagnostics.Contracts
العديد من الأصناف لتَعزيز الشيفرة الخاصة بك بمزيد من الشروط (conditions) اللازم تَحقيقها إمّا خلال وقت التَصْريف أو التَّنْفيذ، مما يُحسِن من فَحْص الشيفرة واكتشاف الأخطاء.
تثبيت المواصفات الاصطلاحية للشيفرة وتفعيلها
يأتي فضاء الاسم System.Diagnostics.Contracts
ضِمْن إطار عمل .NET. لكن ما زلت في حَاجة إلى تَثْبيت الإضافة Code Contracts Tools
ببيئة التطوير المتكاملة فيجوال ستوديو (Visual Studio IDE) حتى تستطيع اِستخدَام المُواصَفَات الاصطلاحيّة للشيفرة (code contracts).
يُمكنك البحث عن Code Contracts
بنافذة الإضافات والتحديثات Extensions and Updates
بفيجوال ستوديو.
يجب أن تُفعِّل خاصية المُواصَفَات الاصطلاحيّة للشيفرة (code contracts) بحل المشروع بعد الإنتهاء من تَثْبيت الإضافة.
تحتاج إلى تَّفْعِيل خاصية الفَحْص الساكن (Static Checking) -فَحْص ما بعد البناء (build)- على الأقل. قد تَرغَب أيضًا بتَّفْعِيل خاصية الفَحْص أثناء التشغيل (Runtime Checking) بالتحديد إذا كنت تُطَوِّر مكتبة (library) ستُستَعَمَل من قِبل حلول (solutions) أُخرى.
الشروط المسبقة (Preconditions)
يَضمَن استخدام الشروط المُسبَقة للتوابع (preconditions) الحد الأدنى من مُتطلَّبات قيم مُعامِلات الدَخْل لتلك التوابع. انظر المثال التالي:
void DoWork(string input) { Contract.Requires(!string.IsNullOrEmpty(input)); //do work }
نتائج تحليل الفَحْص الساكن:
الشروط اللاحقة (Postconditions)
يَضمَن اِستخدَام الشروط اللاحقة للتوابع (postconditions) تَوَافُق النتائج التي تُعيدها تلك التوابع مع التَعرِيف المُخصص للنتائج المتوقعة. يُساعد ذلك على تنْفيذ مُبسَط من خلال إمداد المُحلِّل الساكن (static analyizer) بالعديد من النتائج المُحتَملة. انظر المثال التالي:
string GetValue() { Contract.Ensures(Contract.Result<string>() != null); return null; }
نتائج تحليل الفَحْص الساكن:
إضافة مواصفات اصطلاحيّة للشيفرة إلى الواجهات (interfaces)
يُمكِن أيضًا فَرْض مُواصَفَات اصطلاحيّة للشيفرة (code contracts) على وَاجِهة (interface) عن طريق الإعلان عن صنف مُجرَّد (abstract class) يُنفِّذ هذه الواجهة بشرط أن تُزخرَف الواجهة والصنف المُجرَّد بالسمتين ContractClassAttribute
و ContractClassForAttribute
على الترتيب. انظر المثال التالي:
[ContractClass(typeof(MyInterfaceContract))] public interface IMyInterface { string DoWork(string input); } [ContractClassFor(typeof(IMyInterface))] internal abstract class MyInterfaceContract : IMyInterface { private MyInterfaceContract() { } public string DoWork(string input) { Contract.Requires(!string.IsNullOrEmpty(input)); Contract.Ensures(!string.IsNullOrEmpty(Contract.Result<string>())); throw new NotSupportedException(); } } public class MyInterfaceImplmentation : IMyInterface { public string DoWork(string input) { return input; } }
في المثال بالأعلى، تُعلِّن الواجهة IMyInterface
عن التابع DoWork
الذي يَستقبِل مُعامِلًا من النوع string
. في الحالة العادية، يُمكنك أن تُمرِّر القيمة الفارغة null
إليه. لكن لا يُصبِح ذلك مُمكنًا بعد إضافة المُواصفة الإصطلاحيّة بالأعلى والتي تَستخدِم التابع Contract.Requires
لفَرْض شرط مُسبَق (precondition) بألا يَكون المُعامِل المُمرّر فارغًا.
نتائج تحليل الفَحْص الساكن:
ترجمة -وبتصرف- للفصول System.Diagnostics - Code Contracts - Process and Thread Affinity setting من كتاب .NET Framework Notes for Professionals
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.