Roslyn #1
سکوی کامپایلر دات نت یا Roslyn (با تلفظ «رازلین») بازنویسی مجدد کامپایلرهای VB.NET و #C توسط همین زبانها است. این سکوی کامپایلر به همراه یک سری کتابخانه و اسمبلی ارائه میشود که امکان آنالیز زبانهای مدیریت شده را به صورت مستقل و یا یکپارچهی با ویژوال استودیو، فراهم میکنند. برای نمونه در VS.NET 2015 تمام سرویسهای زبانهای موجود، با Roslyn API جایگزین و بازنویسی شدهاند. نمونههایی از این سرویسهای زبانها، شامل Intellisense و مرور کدها مانند go to references and definitions، به همراه امکانات Refactoring میشوند. به علاوه به کمک Roslyn میتوان یک کامپایلر و ابزارهای مرتبط با آن، مانند FxCop را تولید کرد و یا در نهایت یک فایل اسمبلی نهایی را از آن تحویل گرفت.
چرا مایکروسافت Roslyn را تولید کرد؟
پیش از پروژهی Roslyn، کامپایلرهای VB.NET و #C با زبان ++C نوشته شده بودند؛ از این جهت که در اواخر دههی 90 که کار تولید سکوی دات نت در حال انجام بود، هنوز امکانات کافی برای نوشتن این کامپایلرها با زبانهای مدیریت شده وجود نداشت و همچنین زبان محبوب کامپایلر نویسی در آن دوران نیز ++C بود. این انتخاب در دراز مدت مشکلاتی مانند کاهش انعطاف پذیری و productivity تیم کامپایلر نویس را با افزایش تعداد سطرهای کامپایلر نوشته شده به همراه داشت و افزودن ویژگیهای جدید را به زبانهای VB.NET و #C سختتر و سختتر کرده بود. همچنین در اینجا برنامه نویسهای تیم کامپایلر مدام مجبور بودند که بین زبانهای مدیریت شده و مدیریت نشده سوئیچ کنند و امکان استفادهی همزمان از زبانهایی را که در حال توسعهی آن هستند، نداشتند.
این مسایل سبب شدند تا در طی بیش از یک دهه، چندین نوع کامپایلر از صفر نوشته شوند:
- کامپایلرهای خط فرمانی مانند csc.exe و vbc.exe
- کامپایلر پشت صحنهی ویژوال استودیو (برای مثال کشیدن یک خط قرمز زیر مشکلات دستوری موجود)
- کامپایلر snippetها در immediate window ویژوال استودیو
هر کدام از این کامپایلرها هم برای حل مسایلی خاص طراحی شدهاند. کامپایلرهای خط فرمانی، با چندین فایل ورودی، به همراه ارائهی تعدادی زیادی خطا و اخطار کار میکنند. کامپایلر پشت صحنهی ویژوال استودیوهای تا پیش از نسخهی 2015، تنها با یک تک فایل در حال استفاده، کار میکند و همچنین باید به خطاهای رخ داده نیز مقاوم باشد و بیش از اندازه گزارش خطا ندهد. برای مثال زمانیکه کاربر در حالت تایپ یک سطر است، بدیهی است تا اتمام کار، این سطر فاقد ارزش دستوری صحیحی است و کامپایلر باید به این مساله دقت داشته باشد و یا کامپایلر snippetها تنها جهت ارزیابی یک تک سطر از دستورات وارد شده، طراحی شدهاست.
با توجه به این مسایل، مایکروسافت از بازنویسی سکوی کامپایلر دات نت این اهداف را دنبال میکند:
- بالا بردن سرعت افزودن قابلیتهای جدید به زبانهای موجود
- سبک کردن حجم کاری کامپایلر نویسی و کاهش تعداد آنها به یک مورد
- بالا بردن دسترسی پذیری به API کامپایلرها
برای مثال اکنون برنامه نویسها بجای اینکه یک فایل cs را به کامپایلر csc.exe ارائه کنند و یک خروجی باینری دریافت کنند، امکان دسترسی به syntax trees، semantic analysis و تمام مسایل پشت صحنهی یک کامپایلر را دارند.
- ساده سازی تولید افزونههای مرتبط با زبانهای مدیریت شده.
اکنون برای تولید یک آنالیز کنندهی سفارشی، نیازی نیست هر توسعه دهندهای شروع به نوشتن امکانات پایهای یک کامپایلر کند. این امکانات به صورت یک API عمومی در دسترس برنامه نویسها قرار گرفتهاند.
- آموزش مسایل درونی یک کامپایلر و همچنین ایجاد اکوسیستمی از برنامه نویسهای علاقمند در اطراف آن.
همانطور که اطلاع دارید، Roslyn به صورت سورس باز در GitHub در دسترس عموم است.
تفاوت Roslyn با کامپایلرهای سنتی
اکثر کامپایلرهای موجود به صورت یک جعبهی سیاه عمل میکنند. به این معنا که تعدادی فایل ورودی را دریافت کرده و در نهایت یک خروجی باینری را تولید میکنند. اینکه در این میان چه اتفاقاتی رخ میدهد، از دید استفاده کننده مخفی است.
نمونهای از این کامپایلرهای جعبه سیاه را در تصویر فوق مشاهده میکنید. در اینجا شاید این سؤال مطرح شود که در داخل جعبهی سیاه کامپایلر سیشارپ، چه اتفاقاتی رخ میدهد؟
خلاصهی مراحل رخ داده در کامپایلر سیشارپ را در تصویر فوق ملاحظه میکنید. در اینجا ابتدا کار parse اطلاعات متنی دریافتی شروع میشود و از روی آن syntax tree تولید میشود. در مرحلهی بعد مواردی مانند ارجاعاتی به mscorlib و امثال آن پردازش میشوند. در مرحلهی binder کار پردازش حوزهی دید متغیرها، اشیاء و اتصال آنها به هم انجام میشود. در مرحلهی آخر، کار تولید کدهای IL و اسمبلی باینری نهایی صورت میگیرد.
با معرفی Roslyn، این جعبهی سیاه، به صورت یک API عمومی در دسترس برنامه نویسها قرار گرفتهاست:
همانطور که مشاهده میکنید، هر مرحلهی کامپایل جعبهی سیاه، به یک API عمومی Roslyn نگاشت شدهاست. برای مثال Parser به Syntax tree API نگاشت شدهاست. به علاوه این API صرفا به موارد فوق خلاصه نمیشود و همانطور که پیشتر نیز ذکر شد، برای اینکه بتواند جایگزین سه نوع کامپایلر موجود شود، به همراه Workspace API نیز میباشد:
Roslyn امکان کار با یک Solution و فایلهای آن را دارد و شامل سرویسهای زبانهای مورد نیاز در ویژوال استودیو نیز میشود. برفراز Workspace API، یک مجموعه API دیگر به نام Diagnostics API تدارک دیده شدهاست تا برنامه نویسها بتوانند امکانات Refactoring جانبی را توسعه داده و یا در جهت بهبود کیفیت کدهای نوشته شده، اخطارهایی را به برنامه نویسها تحت عنوان Code fixes و آنالیز کنندهها، ارائه دهند.
RavenDB؛ تجربه متفاوت از پایگاه داده
اساسا از آنجائیکه ما در یک دنیای کامل زندگی نمیکنم و بقولی همه چیزمان باید با همه چیزمان جور دربیاید، ممکن است هنگام استفاده از یک httpWebRequest به خطای زیر برخورد کرده و عملیات دریافت اطلاعات متوقف شود:
و یا حالتی دیگر:
بعضی از وب سروها ممکن است پاسخ ارسالی خود را دقیقا مطابق سطر به سطر RFC های مربوطه ارائه ندهند و کلاس httpWebRequest دات نت هم تعارفی با آنها نداشته و به دلایل امنیتی پردازش پاسخ دریافتی را نیمه کاره رها میکند.
برای مثال content-length دقیقا باید به همین شکل ارسال شود و اگر به صورت content length (با یک فاصله در میان کلمات ارسال گردد) به عنوان یک HTTP response split attack در نظر گرفته شده و خطاهای HTTP protocol violation حاصل میشوند.
اما میتوان آگاهانه دات نت فریم ورک را وادار کرد که از این مساله چشم پوشی کند و این نوع سایتها را نیز بررسی و دریافت نماید. برای این منظور در فایل app.config برنامه ویندوزی خود و یا web.config یک برنامه تحت وب، چند سطر زیر را اضافه کنید:
<configuration>
<system.net>
<settings>
<httpWebRequest useUnsafeHeaderParsing="true" />
</settings>
</system.net>
</configuration>
OpenCVSharp #10
هیستوگرام یک تصویر، توزیع میزان روشنایی آن تصویر را نمایش میدهد و در آن تعداد نقاط قسمتهای روشن تصویر، ترسیم میشوند. محاسبهی هیستوگرام تصاویر در حین دیباگ الگوریتمهای پردازش تصویر، کاربرد زیادی دارند.
OpenCV به همراه متد توکاری است به نام cv::calcHist که قادر است هیستوگرام تعدادی آرایه را محاسبه کند و در C++ API آن قرار دارد. البته هدف اصلی این متد، انجام محاسبات مرتبط است و در اینجا قصد داریم این محاسبات را نمایش دهیم.
تغییر میزان روشنایی و وضوح تصاویر در OpenCV
همانطور که عنوان شد، کار هیستوگرام تصاویر، نمایش توزیع میزان روشنایی نقاط و اجزای آنها است. بنابراین میتوان جهت مشاهدهی تغییر هیستوگرام محاسبه شده با تغییر میزان روشنایی و وضوح تصویر، از متد ذیل کمک گرفت:
private static void updateBrightnessContrast(Mat src, Mat modifiedSrc, int brightness, int contrast) { brightness = brightness - 100; contrast = contrast - 100; double alpha, beta; if (contrast > 0) { double delta = 127f * contrast / 100f; alpha = 255f / (255f - delta * 2); beta = alpha * (brightness - delta); } else { double delta = -128f * contrast / 100; alpha = (256f - delta * 2) / 255f; beta = alpha * brightness + delta; } src.ConvertTo(modifiedSrc, MatType.CV_8UC3, alpha, beta); }
پس از اینکه متد تغییر وضوح تصویر اصلی را تهیه کردیم، میتوان به پنجرهی نمایش تصویر اصلی، دو tracker جهت دریافت brightness و contrast اضافه کرد و به این ترتیب امکان نمایش پویای تغییرات را مهیا نمود:
using (var src = new Mat(@"..\..\Images\Penguin.Png", LoadMode.AnyDepth | LoadMode.AnyColor)) { using (var sourceWindow = new Window("Source", image: src, flags: WindowMode.AutoSize | WindowMode.FreeRatio)) { using (var histogramWindow = new Window("Histogram", flags: WindowMode.AutoSize | WindowMode.FreeRatio)) { var brightness = 100; var contrast = 100; var brightnessTrackbar = sourceWindow.CreateTrackbar( name: "Brightness", value: brightness, max: 200, callback: pos => { brightness = pos; updateImageCalculateHistogram(sourceWindow, histogramWindow, src, brightness, contrast); }); var contrastTrackbar = sourceWindow.CreateTrackbar( name: "Contrast", value: contrast, max: 200, callback: pos => { contrast = pos; updateImageCalculateHistogram(sourceWindow, histogramWindow, src, brightness, contrast); }); brightnessTrackbar.Callback.DynamicInvoke(brightness); contrastTrackbar.Callback.DynamicInvoke(contrast); Cv2.WaitKey(); } } }
پنجرهی دومی نیز به نام هیستوگرام در اینجا تعریف شدهاست. در این پنجره قصد داریم هیستوگرام تغییرات پویای تصویر اصلی را نمایش دهیم.
روش محاسبهی هیستوگرام تصاویر و نمایش آنها در OpenCVSharp
کدهای کامل محاسبهی هیستوگرام تصویر اصلی تغییر یافته (modifiedSrc) و سپس نمایش آنرا در پنجرهی histogramWindow، در ادامه ملاحظه میکنید:
private static void calculateHistogram1(Window histogramWindow, Mat src, Mat modifiedSrc) { const int histogramSize = 64; int[] dimensions = { histogramSize }; // Histogram size for each dimension Rangef[] ranges = { new Rangef(0, histogramSize) }; // min/max using (var histogram = new Mat()) { Cv2.CalcHist( images: new[] { modifiedSrc }, channels: new[] { 0 }, mask: null, hist: histogram, dims: 1, histSize: dimensions, ranges: ranges); using (var histogramImage = (Mat)(Mat.Ones(rows: src.Rows, cols: src.Cols, type: MatType.CV_8U) * 255)) { // Scales and draws histogram Cv2.Normalize(histogram, histogram, 0, histogramImage.Rows, NormType.MinMax); var binW = Cv.Round((double)histogramImage.Cols / histogramSize); var color = Scalar.All(100); for (var i = 0; i < histogramSize; i++) { Cv2.Rectangle(histogramImage, new Point(i * binW, histogramImage.Rows), new Point((i + 1) * binW, histogramImage.Rows - Cv.Round(histogram.Get<float>(i))), color, -1); } histogramWindow.Image = histogramImage; } } }
پس از محاسبهی هیستوگرام، یک تصویر خالی پر شدهی با عدد یک را توسط متد Mat.Ones ایجاد میکنیم. این تصویر به عنوان منبع تصویر هیستوگرام نمایش داده شده، مورد استفاده قرار میگیرد. سپس نیاز است اطلاعات محاسبه شده، در مقیاسی قرار گیرند که قابل نمایش باشد. به همین جهت با استفاده از متد Normalize، آنها را در مقیاس و بازهی ارتفاع تصویر، تغییر اندازه خواهیم داد. سپس به کمک متد مستطیل، خروجی آرایه هیستوگرام را در صفحه، با رنگ خاکستری مشخص شده توسط متد Scalar.All ترسیم خواهیم کرد.
همانطور که در این تصویر ملاحظه میکنید، با کدرتر شدن تصویر اصلی، هیستوگرام آن، توزیع روشنایی کمتری را نمایش میدهد.
کدهای کامل این مثال را از اینجا میتوانید دریافت کنید.
چه نوع محیط کاری را بیشتر ترجیح میدهید؟
- شما در کدها و کوئریهای مثلا EF در اصل با یک سری IQueryable کار میکنید. همینجا باید متد الحاقی ToDataSourceResult را اعمال کنید تا نتیجهی نهایی در حداقل بار تعداد رفت و برگشت و با کوئری مناسبی بر اساس پارامترهای دریافتی به صورت خودکار تولید شود. در انتهای کار بجای مثلا ToList بنویسید ToDataSourceResult.
Vue CLI
- زیرا نیاز به build processهایی داریم که به ما امکان استفاده از ES6, SCSS و دیگر ویژگیهای عالی را خواهند داد.
- جهت ساخت و یکیسازی فایلهای تمپلیت
- بارگذاری نکردن تمامی فایلها به صورت یکجا در زمان Startup
- میتوانیم تسکهایی از قبیل Server-side rendering, code-splitting را انجام دهیم.
npm install -g vue-cli
vue init webpack-simple dntVue
npm install
<template> <div> <!-- Write your HTML with Vue in here --> </div> </template> <script> export default { // Write your Vue component logic here } </script> <style scoped> /* Write your styles for the component in here */ </style>
import { New } from "./components/New.vue"; export default { components: { New } }
npm install -g @vue/cli
3.0.0-beta.11
vue create my-project
Vue CLI v3.0.0-beta.11 ? Please pick a preset: (Use arrow keys) ❯ default (babel, eslint) Manually select features
{ "useConfigFiles": true, "router": true, "vuex": true, "cssPreprocessor": "sass", "plugins": { "@vue/cli-plugin-babel": {}, "@vue/cli-plugin-eslint": { "config": "airbnb", "lintOn": ["save", "commit"] } } }
<!-- MyCard.vue --> <template> <div class="card"> <h1>Card Title</h1> <p>Card content goes here. Make sure it's not Lorem.</p> </div> </template>
npm install -g @vue/cli-service-global
vue serve MyCard.vue
خروجی:
کلاس ArrayList
using System; using System.Collections; class ProgrArrayListExample { static void Main() { ArrayList list = new ArrayList(); list.Add("Hello"); list.Add(5); list.Add(3.14159); list.Add(DateTime.Now); for (int i = 0; i < list.Count; i++) { object value = list[i]; Console.WriteLine("Index={0}; Value={1}", i, value); } } }
Index=0; Value=Hello Index=1; Value=5 Index=2; Value=3.14159 Index=3; Value=29.02.2015 23:17:01
ArrayList list = new ArrayList(); list.Add(2); list.Add(3.5f); list.Add(25u); list.Add(" ریال"); dynamic sum = 0; for (int i = 0; i < list.Count; i++) { dynamic value = list[i]; sum = sum + value; } Console.WriteLine("Sum = " + sum); // Output: Sum = 30.5ریال
مجموعههای جنریک Generic Collections
GenericType<T> instance = new GenericType<T>();
List<int> intList = new List<int>(); List<bool> boolList = new List<bool>(); List<double> realNumbersList = new List<double>();
List<int> intList = new List<int>();
- استفاده از index برای دسترسی به یک مقدار، صرف نظر از اینکه چه میزان دادهای در آن وجود دارد، بسیار سریع انجام میگیرد.
- جست و جوی یک عنصر بر اساس مقدار: جست و جو خطی است در نتیجه اگر مقدار مورد نظر در آخرین خانهها باشد بدترین وضعیت ممکن رخ میدهد و بسیار کند عمل میکند. داده هر چی کمتر بهتر و هر چه بیشتر بدتر. البته اگر بخواهید مجموعهای از مقدارهای برابر را برگردانید هم در بدترین وضعیت ممکن خواهد بود.
- حذف و درج (منظور insert) المانها به خصوص موقعی که انتهای آرایه نباشید، شیفت پیدا کردن در آرایه عملی کاملا کند و زمانبر است.
- موقعی که عنصری را بخواهید اضافه کنید اگر ظرفیت آرایه تکمیل شده باشد، نیاز به عمل زمانبر افزایش ظرفیت خواهد بود که البته این عمل به ندرت رخ میدهد و عملیات افزودن Add هم هیچ وابستگی به تعداد المانها ندارد و عملی سریع است.
- افزودن به انتهای لیست به خاطر این که همیشه گره آخر در tail وجود دارد بسیار سریع است.
- عملیات درج insert در هر موقعیتی که باشد اگر یک اشاره گر به آن محل باشد یک عملیات سریع است یا اینکه درج در ابتدا یاانتهای لیست باشد.
- جست و جوی یک مقدار چه بر اساس اندیس باشد و چه مقدار، کار جست و جو کند خواهد بود. چرا که باید تمامی المانها از اول به آخر اسکن بشن.
- عملیات حذف هم به خاطر اینکه یک عمل جست و جو در ابتدای خود دارد، یک عمل کند است.
استفاده از لیست پیوندی برای پیاده سازی پشته:
Stack<string> stack = new Stack<string>(); stack.Push("A"); stack.Push("B"); stack.Push("C"); while (stack.Count > 0) { string letter= stack.Pop(); Console.WriteLine(letter); } //خروجی //C //B //A
ابتدای آرایه مکانی است که عنصر از آنجا برداشته میشود و Head به آن اشاره میکند و tail هم به انتهای آرایه که جهت درج عنصر جدید مفید است. با برداشتن هر خانهای که head به آن اشاره میکند، head یک خانه به سمت جلو حرکت میکند و زمانی که Head از tail بیشتر شود، یعنی اینکه دیگر عنصری یا المانی در صف وجود ندارد و head و Tail به ابتدای صف حرکت میکنند. در این حالت موقعی که المان جدیدی قصد اضافه شدن داشته باشد، افزودن، مجددا از اول صف آغاز میشود و به این صفها، صف حلقوی میگویند.
عملیات اصلی صف دو مورد هستند enqueue که المان جدید را در انتهای صف قرار میدهد و dequeue اولین المان صف را بیرون میکشد.
پیاده سازی صف به صورت پویا با لیستهای پیوندی
برای پیاده سازی صف، لیستهای پیوندی یک طرفه کافی هستند:
در این حالت عنصر جدید مثل سابق به انتهای لیست اضافه میشود و برای حذف هم که از اول لیست کمک میگیریم و با حذف عنصر اول، متغیر Head به عنصر یا المان دوم اشاره خواهد کرد.
کلاس از پیش آمده صف در دات نت <Queue<T است و نحوهی استفاده آن بدین شکل است:
static void Main() { Queue<string> queue = new Queue<string>(); queue.Enqueue("Message One"); queue.Enqueue("Message Two"); queue.Enqueue("Message Three"); queue.Enqueue("Message Four"); while (queue.Count > 0) { string msg = queue.Dequeue(); Console.WriteLine(msg); } } //خروجی //Message One //Message Two //Message Thre //Message Four