مطالب
بررسی کارآیی کوئری‌ها در SQL Server - قسمت اول - جمع آوری اطلاعات آماری کوئری‌های زنده
بسیاری از شرکت‌ها دارای نقشی مانند «مدیران بانک اطلاعاتی» نیستند؛ اما تعدادی «توسعه دهنده‌ی بانک‌های اطلاعاتی» را به همراه دارند که گاهی از اوقات از آن‌ها خواسته می‌شود تا کارآیی پایین کوئری‌های صورت گرفته را بررسی و رفع کنند و ... آن‌ها دقیقا نمی‌دانند که باید از کجا شروع کنند! فقط می‌دانند که یک کوئری، مدت زمان زیادی را برای اجرا به خود اختصاص می‌دهد؛ اما نمی‌دانند که چگونه باید به کوئری پلن آن دسترسی یافت و چگونه باید آن‌را تفسیر کرد. در این حالت حداکثر کاری را که ممکن است انجام دهند، افزودن یک ایندکس جدید است که ممکن است کار کند و یا خیر و حتی اگر کار کند، دقیقا نمی‌دانند که چگونه! هدف از این سری، بررسی مقدماتی روش‌های بهبود کارآیی کوئری‌ها در SQL Server، از دید یک «توسعه دهنده‌ی بانک‌های اطلاعاتی» است.


پیشنیازهای این سری

در این سری از بانک اطلاعاتی استاندارد مثال به همراه SQL Server 2016، به نام WideWorldImporters استفاده می‌کنیم. برای دریافت آن، به قسمت releases مثال‌های مایکروسافت مراجعه کرده و فایل WideWorldImporters-Full.bak را دریافت کنید. پس از دریافت این فایل، برای restore سریع آن، می‌توانید دستور زیر را اجرا کنید که در آن باید مسیر فایل bak دریافتی و همچنین مسیر ایجاد فایل‌های mdf/ldf/ndf را مطابق مسیرهای سیستم خودتان اصلاح نمائید (فقط مسیر پوشه‌ها را نیاز است تغییر دهید):
use master;

RESTORE DATABASE WideWorldImporters 
FROM disk='D:\path\WideWorldImporters-Full.bak'
WITH MOVE 'WWI_Primary' TO 'D:\SQL_Data\WideWorldImporters.mdf',
MOVE 'WWI_Log' TO 'D:\SQL_Data\WideWorldImporters_log.ldf',
MOVE 'WWI_UserData' TO 'D:\SQL_Data\WideWorldImporters_UserData.ndf',
MOVE 'WWI_InMemory_Data_1' TO 'D:\SQL_Data\WideWorldImporters_InMemory_Data_1'
همچنین صرفنظر از نگارش SQL Server ای که در حال استفاده‌ی از آن هستید (البته به حداقل SQL Server 2016 نیاز خواهید داشت)، بهتر است آخرین نگارش برنامه‌ی management studio را نیز به صورت مستقل دریافت و نصب کنید که در این زمان نگارش 18.1 است.


یافتن اطلاعاتی در مورد کوئری‌ها

SQL Server زمانیکه یک کوئری را اجرا می‌کند، اطلاعاتی را نیز به همراه آن تولید خواهد کرد که سبب ایجاد یک Query Plan می‌شود و در آن، اطلاعاتی مانند جداول مورد استفاده، نوع جوین‌ها، ایندکس‌های استفاده شده و غیره وجود دارند. علاوه بر آن، Query Statistics نیز قابل دسترسی هستند که در آن مدت زمان اجرای یک کوئری، میزان I/O صورت گرفته و میزان مصرف CPU کوئری، ذکر می‌شوند. برای دسترسی یافتن به این اطلاعات، می‌توان به اشیاء مختلف SQL Server مراجعه کرد؛ مانند dynamic management objects یا به اختصار DMO's، همچنین extended events، traces، query stores و یا حتی management studio. مهم‌ترین تفاوت این‌ها نیز در نحوه‌ی دسترسی به اطلاعات آن‌ها است که می‌تواند زنده (live) و یا ذخیره شده در جائی باشند. در اینجا تنها منبعی که امکان مشاهده‌ی این اطلاعات را به صورت زنده میسر می‌کند، management studio است. البته live در اینجا به معنای امکان مشاهده‌ی تمام اطلاعات مرتبط با یک کوئری، مانند آمار و کوئری پلن آن در داخل محیط management studio، پس از اجرای یک کوئری است. در این قسمت بیشتر به روش استخراج اطلاعات آماری کوئری‌های زنده می‌پردازیم و در قسمت‌های بعدی، سایر گزینه‌های نامبرده شده را نیز بررسی خواهیم کرد.


مشاهده‌ی زنده‌ی داده‌های مرتبط با اجرای یک کوئری در management studio

پس از restore بانک اطلاعاتی مثال WideWorldImporters که عنوان شد، در برنامه‌ی Microsoft SQL Server Management Studio، کوئری زیر را اجرا می‌کنیم:
USE [WideWorldImporters];
GO

SELECT
    [s].[StateProvinceName],
    [s].[SalesTerritory],
    [s].[LatestRecordedPopulation],
    [s].[StateProvinceCode]
FROM [Application].[Countries] [c]
    JOIN [Application].[StateProvinces] [s]
    ON [s].[CountryID] = [c].[CountryID]
WHERE [c].[CountryName] = 'United States';
GO
با اجرای آن، اگر به ذیل ردیف‌های بازگشت داده شده‌ی در Management Studio دقت کنیم، مشخص کرده‌است که این کوئری، 53 ردیف را بازگشت داده و همچنین کمتر از 1 ثانیه مدت زمان اجرای آن، طول کشیده‌است:


اینجا است که نیاز به اطلاعات بیشتری در مورد نحوه‌ی اجرای این کوئری داریم. برای استخراج این اطلاعات، اینبار گزینه‌های تولید و جمع آوری اطلاعات آماری IO و TIME را روشن می‌کنیم و سپس همان کوئری قبلی را اجرا خواهیم کرد:
USE [WideWorldImporters];
GO

SET STATISTICS IO ON;
GO
SET STATISTICS TIME ON;
GO

SELECT
    [s].[StateProvinceName],
    [s].[SalesTerritory],
    [s].[LatestRecordedPopulation],
    [s].[StateProvinceCode]
FROM [Application].[Countries] [c]
    JOIN [Application].[StateProvinces] [s]
    ON [s].[CountryID] = [c].[CountryID]
WHERE [c].[CountryName] = 'United States';
GO
ظاهر اجرای این کوئری با کوئری قبلی، تفاوت خاصی ندارد. اما اگر در همینجا به برگه‌ی messages، که در کنار برگه‌ی results و نمایش ردیف‌ها قرار دارد، مراجعه کنیم، یک چنین خروجی قابل مشاهده است:
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 504 ms.

(53 rows affected)
Table 'Countries'. Scan count 0, logical reads 118, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'StateProvinces'. Scan count 1, logical reads 43, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 10 ms.
در اینجا اطلاعات آماری مدت زمان کامپایل و همچنین مدت زمان اجرای کوئری، ارائه شده‌اند. به علاوه در میانه‌ی این آمار، اطلاعات IO کوئری مانند logical reads درج شده‌اند.


استخراج اطلاعات Actual Execution Plan یک کوئری

کوئری را زیر با فرض IO ON و TIME ON حاصل از اجرای کوئری قبل، اجرا می‌کنیم:
USE [WideWorldImporters];
GO

SET STATISTICS XML ON;
GO

SELECT
    [s].[StateProvinceName],
    [s].[SalesTerritory],
    [s].[LatestRecordedPopulation],
    [s].[StateProvinceCode]
FROM [Application].[Countries] [c]
    JOIN [Application].[StateProvinces] [s]
    ON [s].[CountryID] = [c].[CountryID]
WHERE [c].[CountryName] = 'United States';
GO

SET STATISTICS XML OFF;
GO
با فعالسازی اطلاعات آماری XML (و خاموش کردن آن در انتهای کار)، اینبار در برگه‌ی messages، اطلاعات بیشتری ارائه شده‌اند:
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 7 ms.

(53 rows affected)
Table 'Countries'. Scan count 0, logical reads 118, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'StateProvinces'. Scan count 1, logical reads 43, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row affected)

 SQL Server Execution Times:
   CPU time = 15 ms,  elapsed time = 179 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.
اگر دقت کنید اینبار زمان اجرا اندکی بیشتر شده‌است؛ چون درخواست تهیه‌ی query plan را داده‌ایم. این plan را در ذیل قسمت نتایج کوئری می‌توان مشاهده کرد:


اگر بر روی این XML کلیک کنیم، برگه‌ی جدید نمایش گرافیکی این plan ظاهر می‌شود:


با کلیک راست بر روی این برگه، می‌توان اطلاعات آن‌را جهت بررسی‌های بعدی و یا به اشتراک گذاری آن ذخیره کرد.
در این plan اگر اشاره‌گر ماوس را بر روی هر کدام از عناصر آن حرکت دهیم، اطلاعاتی مانند actual number of rows نیز مشاهده می‌شود، در کنار اطلاعات تخمینی؛ به همین جهت به آن Actual Execution Plan هم گفته می‌شود.


این یک روش دسترسی به Execution Plan است. روش دوم آن با استفاده از امکانات رابط کاربری خود Management Studio است؛ با فشردن دکمه‌های Ctrl+M و یا انتخاب گزینه‌ی Include actual execution plan از منوی Query آن. پس از آن کوئری زیر را اجرا کنید:
SET STATISTICS IO ON;
GO
SET STATISTICS TIME ON;
GO

SELECT
    [s].[StateProvinceName],
    [s].[SalesTerritory],
    [s].[LatestRecordedPopulation],
    [s].[StateProvinceCode]
FROM [Application].[Countries] [c]
    JOIN [Application].[StateProvinces] [s]
    ON [s].[CountryID] = [c].[CountryID]
WHERE [c].[CountryName] = 'United States';
GO
اینبار در برگه‌ی نتایج کوئری، برگه‌ی سوم Execution Plan قابل مشاهده‌است:




استخراج اطلاعات Estimated Execution Plan یک کوئری

تا اینجا نحوه‌ی استخراج اطلاعات Actual Execution Plan را بررسی کردیم که به همراه اطلاعات دقیق حاصل از اجرای کوئری نیز بود؛ مانند actual number of rows. نوع دیگری از Execution Planها را نیز می‌توان از SQL Server درخواست کرد که به آن‌ها Estimated Execution Plan گفته می‌شود و حاصل اجرای کوئری نیستند؛ بلکه تخمینی هستند از روش اجرای این کوئری توسط SQL Server. برای فعالسازی محاسبه‌ی آن، ابتدا کوئری زیر را در management studio انتخاب کنید:
USE [WideWorldImporters];
GO

SELECT
    [s].[StateProvinceName],
    [s].[SalesTerritory],
    [s].[LatestRecordedPopulation],
    [s].[StateProvinceCode]
FROM [Application].[Countries] [c]
    JOIN [Application].[StateProvinces] [s]
    ON [s].[CountryID] = [c].[CountryID]
WHERE [c].[CountryName] = 'United States';
GO
سپس از منوی Query، گزینه‌ی Display estimated execution plan را انتخاب نمائید و یا دکمه‌های Ctrl+L را فشار دهید. در این حالت برگه‌های حاصل، حاوی قسمت results نیستند؛ چون کوئری اجرا نشده‌است. اما هنوز برگه‌ی Execution Plan قابل مشاهده است:


همانطور که مشاهده می‌کنید، اینبار نتیجه‌ی حاصل، به همراه اطلاعاتی مانند actual number of rows نیست و صرفا تخمینی است از روش اجرای این کوئری، توسط SQL Server.


جمع آوری اطلاعات آماری کلاینت‌ها

در منوی Query، گزینه‌ای تحت عنوان Include client statistics نیز وجود دارد. با انتخاب آن، اگر کوئری زیر را اجرا کنیم:
USE [WideWorldImporters];
GO

SELECT
    [s].[StateProvinceName],
    [s].[SalesTerritory],
    [s].[LatestRecordedPopulation],
    [s].[StateProvinceCode]
FROM [Application].[Countries] [c]
    JOIN [Application].[StateProvinces] [s]
    ON [s].[CountryID] = [c].[CountryID]
WHERE [c].[CountryName] = 'United States';
GO
اینبار برگه‌ی جدید client statistics ظاهر می‌شود:


در اینجا مشخص می‌شود که آیا عملیات insert/update/delete انجام شده‌است. چه تعداد ردیف تحت تاثیر اجرای این کوئری قرار گرفته‌اند. چه تعداد تراکنش انجام شده‌است. همچنین اطلاعات آماری شبکه و زمان نیز در اینجا ارائه شده‌اند.
در همین حالت، کوئری جدید زیر را با تغییر قسمت where کوئری قبلی، اجرا کنید:
SELECT
    [s].[StateProvinceName],
    [s].[SalesTerritory],
    [s].[LatestRecordedPopulation],
    [s].[StateProvinceCode]
FROM [Application].[Countries] [c]
    JOIN [Application].[StateProvinces] [s]
    ON [s].[CountryID] = [c].[CountryID]
WHERE [s].[StateProvinceName] LIKE 'O%';
GO
نتیجه‌ی آن، ظاهر شدن ستون جدید trial 2 است که می‌تواند جهت مقایسه‌ی کوئری‌های مختلف با هم، بسیار مفید باشد:


در اینجا حداکثر 10 کوئری را می‌توان با هم مقایسه کرد و بیشتر از آن سبب حذف موارد قدیمی از لیست می‌شود.


عدم نمایش ردیف‌های بازگشت داده شده‌ی توسط کوئری در حین جمع آوری اطلاعات آماری

هربار اجرای یک کوئری در management studio، به همراه بازگشت و نمایش ردیف‌های مرتبط با آن کوئری نیز می‌باشد. اگر می‌خواهید در حین بررسی کارآیی کوئری‌ها از نمایش این ردیف‌ها صرف نظر کنید (تا بار این برنامه کاهش یابد)، می‌توانید از منوی Query، گزینه‌ی Query Options را انتخاب کرده و در قسمت Results، گزینه‌ی Grid آن، گزینه‌ی discard results after execution را انتخاب کنید تا دیگر برگه‌ی results نمایش داده نشود و وقت و منابع را تلف نکند. بدیهی است پس از پایان کار بررسی آماری، نیاز به عدم انتخاب این گزینه خواهد بود.
مطالب
تنظیمات و نکات کاربردی کتابخانه‌ی JSON.NET
پس از بررسی مقدماتی امکانات کتابخانه‌ی JSON.NET، در ادامه به تعدادی از تنظیمات کاربردی آن با ذکر مثال‌هایی خواهیم پرداخت.


گرفتن خروجی CamelCase از JSON.NET

یک سری از کتابخانه‌های جاوا اسکریپتی سمت کلاینت، به نام‌های خواص CamelCase نیاز دارند و حالت پیش فرض اصول نامگذاری خواص در دات نت عکس آن است. برای مثال بجای UserName به userName نیاز دارند تا بتوانند صحیح کار کنند.
روش اول حل این مشکل، استفاده از ویژگی JsonProperty بر روی تک تک خواص و مشخص کردن نام‌های مورد نیاز کتابخانه‌ی جاوا اسکریپتی به صورت صریح است.
روش دوم، استفاده از تنظیمات ContractResolver می‌باشد که با تنظیم آن به CamelCasePropertyNamesContractResolver به صورت خودکار به تمامی خواص به صورت یکسانی اعمال می‌گردد:
var json = JsonConvert.SerializeObject(obj, new JsonSerializerSettings
{
   ContractResolver = new CamelCasePropertyNamesContractResolver()
});


درج نام‌های المان‌های یک Enum در خروجی JSON

اگر یکی از عناصر در حال تبدیل به JSON، از نوع enum باشد، به صورت پیش فرض مقدار عددی آن در JSON نهایی درج می‌گردد:
using Newtonsoft.Json;

namespace JsonNetTests
{
    public enum Color
    {
        Red,
        Green,
        Blue,
        White
    }

    public class Item
    {
        public string Name { set; get; }
        public Color Color { set; get; }
    }

    public class EnumTests
    {
        public string GetJson()
        {
            var item = new Item
            {
                Name = "Item 1",
                Color = Color.Blue 
            };

            return JsonConvert.SerializeObject(item, Formatting.Indented);
        }
    }
}
با این خروجی:
{
  "Name": "Item 1",
  "Color": 2
}
اگر علاقمند هستید که بجای عدد 2، دقیقا مقدار Blue در خروجی JSON درج گردد، می‌توان به یکی از دو روش ذیل عمل کرد:
الف) مزین کردن خاصیت از نوع enum به ویژگی JsonConverter از نوع StringEnumConverter:
  [JsonConverter(typeof(StringEnumConverter))]
  public Color Color { set; get; }
ب) و یا اگر می‌خواهید این تنظیم به تمام خواص از نوع enum به صورت یکسانی اعمال شود، می‌توان نوشت:
return JsonConvert.SerializeObject(item, new JsonSerializerSettings
{
   Formatting = Formatting.Indented,
   Converters = { new StringEnumConverter() }
});


تهیه خروجی JSON از مدل‌های مرتبط، بدون Stack overflow

دو کلاس گروه‌های محصولات و محصولات ذیل را درنظر بگیرید:
   public class Category
    {
        public int Id { get; set; }
        public string Name { get; set; }

        public virtual ICollection<Product> Products { get; set; }

        public Category()
        {
            Products = new List<Product>();
        }
    }

    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }

        public virtual Category Category { get; set; }
    }
این نوع طراحی در Entity framework بسیار مرسوم است. در اینجا طرف‌های دیگر یک رابطه، توسط خاصیتی virtual معرفی می‌شوند که به آن‌ها خواص راهبری یا navigation properties هم می‌گویند.
با توجه به این دو کلاس، سعی کنید مثال ذیل را اجرا کرده و از آن، خروجی JSON تهیه کنید:
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

namespace JsonNetTests
{
    public class SelfReferencingLoops
    {
        public string GetJson()
        {
            var category = new Category
            {
                Id = 1,
                Name = "Category 1"
            };
            var product = new Product
            {
                Id = 1,
                Name = "Product 1"
            };

            category.Products.Add(product);
            product.Category = category;

            return JsonConvert.SerializeObject(category, new JsonSerializerSettings
            {
                Formatting = Formatting.Indented,
                Converters = { new StringEnumConverter() }
            });
        }
    }
}
برنامه با این استثناء متوقف می‌شود:
 An unhandled exception of type 'Newtonsoft.Json.JsonSerializationException' occurred in Newtonsoft.Json.dll
Additional information: Self referencing loop detected for property 'Category' with type 'JsonNetTests.Category'. Path 'Products[0]'.
اصل خطای معروف فوق «Self referencing loop detected» است. در اینجا کلاس‌هایی که به یکدیگر ارجاع می‌دهند، در حین عملیات Serialization سبب بروز یک حلقه‌ی بازگشتی بی‌نهایت شده و در آخر، برنامه با خطای stack overflow خاتمه می‌یابد.

راه حل اول:
به تنظیمات JSON.NET، مقدار ReferenceLoopHandling = ReferenceLoopHandling.Ignore را اضافه کنید تا از حلقه‌ی بازگشتی بی‌پایان جلوگیری شود:
return JsonConvert.SerializeObject(category, new JsonSerializerSettings
{
   Formatting = Formatting.Indented,
   ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
   Converters = { new StringEnumConverter() }
});
راه حل دوم:
به تنظیمات JSON.NET، مقدار PreserveReferencesHandling = PreserveReferencesHandling.Objects را اضافه کنید تا مدیریت ارجاعات اشیاء توسط خود JSON.NET انجام شود:
return JsonConvert.SerializeObject(category, new JsonSerializerSettings
{
   Formatting = Formatting.Indented,
   PreserveReferencesHandling = PreserveReferencesHandling.Objects,
   Converters = { new StringEnumConverter() }
});
خروجی حالت دوم به این شکل است:
{
  "$id": "1",
  "Id": 1,
  "Name": "Category 1",
  "Products": [
    {
      "$id": "2",
      "Id": 1,
      "Name": "Product 1",
      "Category": {
        "$ref": "1"
      }
    }
  ]
}
همانطور که ملاحظه می‌کنید، دو خاصیت $id و $ref توسط JSON.NET به خروجی JSON اضافه شده‌است تا توسط آن بتواند ارجاعات و نمونه‌های اشیاء را تشخیص دهد.
مطالب
تغییرات اعمال شده در C++11 قسمت اول (enum)
نوع شمارشی enum
نوع شمارشی، یک نوع صحیح است و شامل لیستی از ثوابت می‌باشد که توسط برنامه نویس مشخص می‌گردد . انواع شمارشی برای تولید کد  خودمستند  به کار می‌روند یعنی کدی که به راحتی قابل درک باشد و نیاز به توضیحات اضافه نداشته باشد. زیرا به راحتی توسط نام ، نوع کاربرد و محدوده مقادیرشان قابل درک می‌باشند . مقادیر نوع شمارشی منحصربه فرد می‌باشند (unique) و شامل مقادیر تکراری نمی‌باشند در غیر این صورت  کامپایلر خطای مربوطه را هشدار میدهد . نحوه تعریف نوع شمارشی :
enum typename{enumerator-list}
enum کلمه کلیدی ست ، typename  نام نوع جدید است که برنامه نویس مشخص میکند و enumerator-list مجموعه مقادیری ست که این نوع جدید می‌تواند داشته باشد بعنوان مثال :
enum Day{SAT,SUN,MON,TUE,WED,THU,FRI}
اکنون Day  یک نوع جدید است و متغیرهایی که از این نوع تعریف می‌شوند میتوانند یکی از مقادیر مجموعه فوق را دارا باشند .
Day  day1,day2; 
day1 = SAT; 
day2 = SUN;
مقادیرSAT و SUN و MON  هر چند که به همین شکل بکار میروند ولی در رایانه به شکل اعداد صحیح  0 , 1 , 2 , ... ذخیره می‌شوند . به همین دلیل است که به هر یک از مقادیر SAT و SUN و ...  یک شـمارشـگر می‌گویند . وقتی فهرست شمارشگرهای یک نوع تعریف شد به طور خودکار مقادیر 0 و 1 و ... به ترتیب به آنها اختصاص داده میشود . می‌توان مقادیر صحیح دلخواهی به شمارشگرها نسبت داد به طور مثال :
enum Day{SAT=1,SUN=2,MON=4,TUE=8,WED=16,THU=32,FRI=64}
اگر چند شمارشگر مقدار دهی شده باشند آنگاه شمارشگرهایی که مقدار دهی نشده اند ، مقادیر متوالی بعدی را خواهند گرفت .
enum Day{SAT=1,SUN,MON,TUE,WED,THU,FRI}
دستور بالا مقادیر 1 تا 7 را بترتیب به شمارشگرها اختصاص میدهد .
میتوان به شمارشگرها مقادیر یکسانی نسبت داد
enum Answer{NO=0,FALSE=0,YES=1,TRUE=1,OK=1}
ولی نمی‌توان نامهای یکسانی را در نظر گرفت  ! تعریف زیر بدلیل استفاده مجدد از شمارشگر YES با خطای کامپایلر مواجه می‌شویم .
enum Answer{NO=0,FALSE=0,YES=1,YES=2,OK=1}
چند دلیل استفاده از نوع شمارشی عبارت است از :
1- enum سبب میشود که شما مقادیر مجاز و قابل انتظار را به متغیرهایتان نسبت دهید .
2- enum  اجازه میدهد با استفاده از نام به مقدار دستیابی پیدا کنید پس کدهایتان خواناتر میشود .
3- با استفاده از enum  تایپ کدهایتان سریع میشود زیرا IntelliSense در مورد انتخاب گزینه مناسب شما را یاری میدهد .

چند تعریف از enum :
enum Color{RED,GREEN,BLUE,BLACK,ORANGE} 
enum Time{SECOND,MINUTE,HOUR} 
enum Date{DAY,MONTH,YEAR} 
enum Language{C,DELPHI,JAVA,PERL} 
enum Gender{MALE,FEMALE}
تا اینجا خلاصه ای از enum و مفهوم آن داشتیم

اما تغییراتی که در  c++11 اعمال شده : Type-Safe Enumerations 

فرض کنید دو enum  تعریف کرده اید و به شکل زیر می‌باشد
enum Suit {Clubs, Diamonds, Hearts, Spades};
enum Jewels {Diamonds, Emeralds, Opals, Rubies, Sapphires};
اگر این دستورات را کامپایل کنید با خطا مواجه می‌شوید چون در هر دو enum  شمارشگر Diamonds تعریف شده است . کامپایلر اجازه تعریف جدیدی از یک شمارشگر در enum  دیگری نمیدهد هر چند برخی اوقات مانند مثال بالا نیازمند تعریف یک شمارشگر در چند enum  بر حسب نیاز میباشیم .
برای تعریف جدیدی که در  c++11 داده شده کلمه کلیدی  class  بعد از کلمه enum  مورد استفاده قرار میگیرد . به طور مثال تعریف دو enum  پیشین که با خطا مواجه میشد بصورت زیر تعریف میشود و از کامپایلر خطایی دریافت نمیکنیم .
enum class Suit {Clubs, Diamonds, Hearts, Spades};
enum class Jewels {Diamonds, Emeralds, Opals, Rubies, Sapphires};
همچنین استفاده از enum در گذشته و تبدیل آن به شکل زیر بود :
enum Suit {Clubs, Diamonds, Hearts, Spades};
Suit var1 = Clubs;
int var2= Clubs;
یک متغیر از نوع Suit بنام var1  تعریف میکنیم و شمارشگر Clubs را به آن نسبت میدهیم ، خط بعد متغیری از نوع int تعریف نمودیم و مقدار شمارشگر Clubs که 0 می‌باشد را به آن نسبت دادیم . اما اگر تعریف enum  را با قوائد C++11  در نظر بگیریم این نسبت دادنها باعث خطای کامپایلر میشود و برای نسبت دادن صحیح باید به شکل زیر عمل نمود .
enum class Jewels {Diamonds, Emeralds, Opals, Rubies, Sapphires};
Jewels typeJewel = Jewels::Emeralds;
int suitValue = static_cast<int>(typeJewel);
همانطور که مشاهده میکنید ، Type-Safe یودن enum  را نسبت به تعریف گذشته آن مشخص می‌باشد .
یک مثال کلی و جامع‌تر :
// Demonstrating type-safe and non-type-safe enumerations
#include <iostream>
using std::cout;
using std::endl;
// You can define enumerations at global scope
//enum Jewels {Diamonds, Emeralds, Rubies}; // Uncomment this for an error
enum Suit : long {Clubs, Diamonds, Hearts, Spades};
int main()
{
// Using the old enumeration type...
Suit suit = Clubs; // You can use enumerator names directly
Suit another = Suit::Diamonds; // or you can qualify them
// Automatic conversion from enumeration type to integer
cout << "suit value: " << suit << endl;
cout << "Add 10 to another: " << another + 10 << endl;
// Using type-safe enumerations...
enum class Color : char {Red, Orange, Yellow, Green, Blue, Indigo, Violet};
Color skyColor(Color::Blue); // You must qualify enumerator names
// Color grassColor(Green); // Uncomment for an error
// No auto conversion to numeric type
cout << endl
<< "Sky color value: "<< static_cast<long>(skyColor) << endl;
//cout << skyColor + 10L << endl; // Uncomment for an error
cout << "Incremented sky color: "
<< static_cast<long>(skyColor) + 10L // OK with explicit cast
<< endl;
return 0;
}
مطالب
مدیریت رجیستری در #C

رجیستری یک پایگاه داده‌ی سیستمی است که برنامه‌ها، اجزای سیستم و اطلاعات پیکربندی در آن ذخیره و بازیابی می‌شود. داده‌های ذخیره شده در رجیستری مطابق با نسخه ویندوز فرق می‌کنند. نرم‌افزارها برای بازیابی، تغییر و پاک کردن رجیستری از API ‌های مختلفی استفاده می‌کنند. خوشبختانه .NET نیز امکانات لازم برای مدیریت رجیستری را فراهم کرده است.

در صورت رخداد خطا در رجیستری، امکان خراب شدن ویندوز وجود دارد در نتیجه با احتیاط عمل کنید و قبل از هر کاری  از رجیستری پشتیبان تهیه نمایید. قبل از شروع به کدنویسی قدری با ساختار رجیستری آشنا شویم تا در ادامه قادر به درک مفاهیم باشیم.

ساختار رجیستری

رجیستری اطلاعات را در ساختار درختی نگاه می‌دارد. هر گره در درخت، یک کلید ( key ) نامیده می‌شود. هر کلید می‌تواند شامل چندین زیرکلید ( subkey ) و چندین مقدار ( value ) باشد. در برخی موارد، وجود یک کلید تمام اطلاعاتی است که نرم افزار بدان نیاز دارد و در برخی موارد، برنامه کلید را باز کرده و مقادیر مربوط به آن کلید را می‌خواند. یک کلید می‌تواند هر تعداد مقدار داشته باشد و مقادیر به هر شکلی می‌توانند باشند. هر کلید شامل یک یا چند کاراکتر است. نام کلیدها نمی‌توانند کاراکتر “\” را داشته باشند. نام هر زیرکلید یکتاست و وابسته به کلیدی است که در سلسله مراتب، بلافاصله بالای آن می‌آید. نام کلیدها باید انگلیسی باشند اما مقادیر را به هر زبانی می‌توان نوشت. در زیر یک نمونه از ساختار رجیستری را مشاهده می‌کنید که در نرم‌افزار registry editor به نمایش در آمده است.

هر کدام از درخت‌های زیر my computer یک کلید است. HKEY_LOCAL_MACHINE دارای زیرکلید‌هایی مثل HARDWARE ، SAM و SECURITY است. هر مقدار شامل یک اسم، نوع و داده‌های درون آن است. برای مثال MaxObjectNumber از مقادیر زیرکلید HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\VIDEO است. داده‌های درون هر مقدار می‌تواند از انواع باینری، رشته‌ای و عددی باشد؛ برای مثال MaxObjectNumber یک عدد ۳۲ بیتی است.

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

اطلاعات رجیستری در پیج فایل ( Page File ) ذخیره می‌شوند. پیج فایل ناحیه‌ای از حافظه RAM است که می‌تواند در زمانی که استفاده نمی‌شود به Hard منتقل شود. اندازه‌ی پیج فایل به وسیله‌ی مقدار PagedPoolSize در کلید HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management مطابق با جدول زیر تنظیم می‌گردد.

مقدار

توضیحات

0×00000000

سیستم یک مقدار بهینه را تعیین می‌کند

0x1–0x20000000

یک اندازه مشخص برحسب بایت که در این بازه باشد

0xFFFFFFFF

سیستم بیش‌ترین مقدار ممکن را تشخیص می‌دهد

کلیدهای از پیش تعریف شده

یک برنامه قبل از آن که اطلاعاتی را در رجیستری درج کند باید یک کلید را باز کند. برای باز کردن یک کلید می‌توان از سایر کلیدهایی که باز هستند، استفاده کرد. سیستم کلیدهایی را از پیش تعریف کرده که همیشه باز هستند. در ادامه کلیدهای از پیش تعریف شده را قدری بررسی می‌کنیم.

HKEY_CLASSES_ROOT

زیرشاخه‌های این کلید، انواع اسناد و خصوصیات مربوط به آن‌ها را مشخص می‌کنند. این شاخه نباید در یک سرویس یا برنامه‌ای که کاربران متعدد دارد، مورد استفاده قرار گیرد.

HKEY_CURRENT_USER

زیرشاخه‌های این کلید، تنظیمات مربوط به کاربر جاری را مشخص می‌کنند. این تنظیمات شامل متغیرهای محیطی، اطلاعات درباره‌ی برنامه‌ها، رنگ‌ها، پرینترها، ارتباطات شبکه و تنظیمات برنامه‌هاست. به طور مثال مایکروسافت اطلاعات مربوط به برنامه‌های خود را در کلید HKEY_CURRENT_USER\Software\Microsoft ذخیره می‌کند. هر کدام از برنامه‌ها یک زیرکلید در کلید مزبور را به خود اختصاص داده‌اند. این شاخه نیز نباید در یک سرویس یا برنامه‌ای که کاربران متعدد دارد، مورد استفاده قرار گیرد.

HKEY_LOCAL_MACHINE

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

HKEY_USERS

زیرشاخه‌های این کلید، پیکربندی کاربران پیش فرض، جدید، جاری سیستم و به طور کلی همه‌ی کاربران را مشخص می‌کند.

HKEY_CURRENT_CONFIG

زیرشاخه‌های این کلید، اطلاعاتی درباره وضعیت سخت‌افزار کامپیوتر در اختیار ما می‌گذارند. در واقع این کلید نام مستعاری برای کلید HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Hardware Profiles\Current است که در ویندوزهای قبل از ۳.۵۱ NT وجود نداشته است.

کندوهای رجیستری

یک کندو ( Hive ) یک گروه از کلیدها، زیرکلیدها و مقادیر در رجیستری است که یک مجموعه از فایل‌های پشتیبان را به همراه دارد. در هنگام بوت ویندوز، اطلاعات از این فایل‌ها استخراج می‌شوند. شما هم چنین می‌توانید با استفاده از Import در منوی فایل registry editor به صورت دستی این کار را انجام دهید. زمانی که ویندوز را خاموش می‌کنید، اطلاعات کندوها در فایل‌های پشتیبان نوشته می‌شوند. شما می‌توانید این کار را به طور دستی با Export در منوی فایل registry editor نیز انجام دهید.

فایل‌های پشتیبان همه کندوها به جز HKEY_CURRENT_USER در شاخه‌ی Windows Root\System32\config قرار دارند. فایل‌های پشتیبان HKEY_CURRENT_USER در شاخه‌ی System Root\Documents and Settings\Username قرار دارند. پسوند فایل‌ها در این شاخه‌ها، نوع داده‌هایی که در بر دارند را نشان می‌دهند. در جدول زیر برخی کندوها و فایل‌های پشتیبانشان آمده است.

کندوی رجیستری

فایل‌های پشتیبان

HKEY_CURRENT_CONFIG

System, System.alt, System.log, System.sav

HKEY_CURRENT_USER

Ntuser.dat, Ntuser.dat.log

HKEY_LOCAL_MACHINE\SAM

Sam, Sam.log, Sam.sav

HKEY_LOCAL_MACHINE\Security

Security, Security.log, Security.sav

HKEY_LOCAL_MACHINE\Software

Software, Software.log, Software.sav

HKEY_LOCAL_MACHINE\System

System, System.alt, System.log, System.sav

HKEY_USERS\.DEFAULT

Default, Default.log, Default.sav

هر زمان که یک کاربر به کامپیوتر وارد می‌شود، یک کندوی جدید با فایل‌های مجزا برای آن کاربر ساخته می‌شود که کندوی پروفایل کاربر نام دارد. یک کندوی کاربر، اطلاعاتی شامل تنظیمات برنامه‌های کاربر، تصویر زمینه، ارتباطات شبکه و پرینترها را در بر دارد. کندوهای پروفایل کاربر در کلید HKEY_USERS قرار دارند. مسیر فایل‌های پشتیبان این کندوها در کلید HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\SID\ ProfileImagePath مشخص شده است. مقدار ProfileImagePath مسیر پروفایل کاربر و نام کاربر را مشخص می‌کند.

دسته بندی اطلاعات


قبل از قرار دادن اطلاعات در رجیستری باید آن‌ها را به دو دسته اطلاعات کامپیوتر و اطلاعات کاربر تقسیم کرد. با این تقسیم بندی، چندین کاربر می‌توانند از یک برنامه استفاده کنند و یا اطلاعات را بر روی شبکه قرار دهند. زمانی که یک برنامه نصب می‌شود، باید اطلاعات کامپیوتری خود را در شاخه فرضی
HKEY_LOCAL_MACHINE\Software\MyCompany\MyProduct\1.0 به گونه‌ای تعریف کند که نام شرکت، نام محصول و نسخه برنامه به خوبی مشخص گردند و هم چنین اطلاعات مربوط به کاربران را در شاخه فرضی HKEY_CURRENT_USER\Software\MyCompany\MyProduct\1.0 نگاه دارد.

باز کردن، ساختن و بستن کلیدها


قبل از آن که بتوانیم یک اطلاعات را در رجیستری درج کنیم، باید یک کلید بسازیم و یا یک کلید موجود را باز کنیم. یک برنامه همیشه به یک کلید به عنوان زیرکلیدی از یک کلید باز رجوع می‌کند. کلیدهای از پیش تعریف شده همیشه باز هستند.

کلاس‌های تعریف شده برای کار با رجیستری در فضانام Microsoft.Win32 قرار دارند. کلاس Microsoft.Win32.Registry مربوط به کلاس‌های از پیش تعریف شده و کلاس Microsoft.Win32.RegistryKey برای کار با رجیستری است. برای باز کردن یک کلید از متد RegistryKey.OpenSubKey استفاده می‌کنیم. به یاد داشته باشید که کلیدهای از پیش تعریف شده همیشه باز هستند و نیازی به باز کردن ندارند. برای ساختن یک کلید از متد RegistryKey.CreateSubKey استفاده می‌کنیم. دقت کنید زیرکلیدی که می‌خواهید بسازید، باید به یک کلید باز رجوع کند. برای خاتمه دسترسی به یک کلید، باید آن را ببندیم. برای بستن یک کلید از متد RegistryKey.Close استفاده می‌کنیم.

اکنون که با ساختار رجیستری و کلاس‌های مربوطه در .NET برای کار با رجیستری آشنا شدیم، به کدنویسی می‌پردازیم.

ساختن یک زیرکلید جدید

برای ساختن یک زیرکلید جدید از متد RegistryKey.CreateSubKey به صورت زیر استفاده می‌کنیم.

public RegistryKey CreateSubKey( string subkey);

subkey نام و مسیر کلیدی که می‌خواهید بسازید را مشخص می‌کند که معمولا به فرم فرضی key name\Company Name\Application Name\version است. این متد یک زیرکلید را برمی‌گرداند و در صورت بروز خطا مقدار null را برمی‌گرداند و یک exception را فرا می‌خواند. خطا به دلایلی چون عدم داشتن مجوز، وجود نداشتن مسیر درخواستی و غیره رخ می‌دهد. برای بررسی exception ‌ها می‌توانید از بلوک try-catch استفاده کنید.

RegistryKey MyReg = Registry .CurrentUser.CreateSubKey( "SOFTWARE\\SomeCompany\\SomeApp\\SomeVer" );
مثال فوق یک زیرکلید جدید در مسیر تعیین شده در شاخه‌ی HKEY_CURRENT_USER می‌سازد.

برای دست یابی به کلیدهای از پیش تعریف شده از کلاس Registry مطابق جدول زیر استفاده می‌کنیم.

فیلد

کلید

ClassesRoot

HKEY_CLASSES_ROOT

CurrentUser

HKEY_CURRENT_USER

LocalMachine

HKEY_LOCAL_MACHINE

Users

HKEY_USERS

CurrentConfig

HKEY_CURRENT_CONFIG

چند نکته حائز اهمیت است. اگر یک زیرکلید با نام مشابه در مسیر تعیین شده وجود داشته باشد، هیچ کلیدی ساخته نمی‌شود. حقیقت آن است که از متد CreateSubKey برای باز کردن یک کلید نیز می‌توانیم استفاده کنیم. متد CreateSubKey زیرکلید را همیشه در حالت ویرایش بازمی‌گرداند. متد CreateSubKey دو پارامتر دیگر به عنوان ورودی دریافت می‌کند که از دو کلاس RegistryKeyPermissionCheck و RegistryOptions استفاده می‌کند. RegistryKeyPermissionCheck مشخص می‌کند که درخت زیرکلید، فقط خواندنی یا قابل ویرایش باشد. RegistryOptions مشخص می‌کند که اطلاعات کلید فقط در حافظه‌ی اصلی باشد و دیگر به کندوها منتقل نشود یعنی به طور موقتی باشد یا به طور پیش فرض دائمی باشد.

باز کردن زیرکلید موجود


برای باز کردن یک زیرکلید موجود از متد
RegistryKey.OpenSubKey به دو صورت استفاده می‌کنیم.
public RegistryKey OpenSubKey( string name);
public RegistryKey OpenSubKey( string name, bool writable);
صورت اول، کلید را در حالت فقط خواندنی باز می‌کند و صورت دوم، اگر writable ، true باشد کلید را در حالت ویرایش باز می‌کند و اگر false باشد کلید را در حالت فقط خواندنی باز می‌کند. در هر دو صورت name ، نام و مسیر زیرکلیدی که می‌خواهید باز کنید را مشخص می‌کند. اگر با خطا مواجه نشوید، متد زیرکلید را برمی‌گرداند، در غیر این صورت مقدار null را برمی‌گرداند.
RegistryKey MyReg = Registry .CurrentUser.OpenSubKey( "SOFTWARE\\SomeCompany\\SomeApp\\SomeVer" , true );

مثال فوق کلید مشخص شده را در شاخه‌ی HKEY_CURRENT_USER و در حالت ویرایش باز می‌کند.

خواندن اطلاعات از رجیستری

اگر یک شیء RegistryKey سالم داشته باشید می‌توانید به مقادیر و اطلاعات درون مقادیر آن دسترسی داشته باشید. برای دست یابی به اطلاعات درون یک مقدار مشخص در کلید از متد RegistryKey.GetValue به دو صورت استفاده کنیم.

public object GetValue( string name);
public object GetValue( string name, object defaultValue);
صورت اول، اطلاعات درون مقداری با نام و مسیر name را برمی‌گرداند. اگر مقدار مذکور وجود نداشته باشد، مقدار null را برمی‌گرداند. درصورت دوم اگر مقدار خواسته شده وجود نداشته باشد، defaultValue را برمی‌گرداند. متد GetValue یک مقدار از نوع object را برمی‌گرداند در نتیجه شما برای استفاده، باید آن را به نوعی که می‌خواهید تبدیل کنید.

نوشتن اطلاعات در رجیستری


برای نوشتن اطلاعات در یک مقدار از متد
RegistryKey.SetValue به صورت زیر استفاده می‌کنیم.
public void SetValue( string name, object value);
رشته name ، نام مقداری که اطلاعات باید در آن ذخیره شود و value اطلاعاتی که باید در آن مقدار ذخیره شود را مشخص می‌کنند. چون value از نوع object است می‌توانید هر مقداری را به آن بدهید. Vallue به طور اتوماتیک به DWORD یا باینری یا رشته‌ای تبدیل می‌شود. البته یک پارامتر سومی نیز وجود دارد که از کلاس RegistryValueKind استفاده کرده و نوع اطلاعات را به طور دقیق مشخص می‌کند. برای ذخیره اطلاعات در مقدار پیش فرض ( Default ) کافی است که مقدار name را برابر string.Empty قرار دهید. هر کلید می‌تواند یک مقدار پیش فرض داشته باشد که باید نام آن مقدار را Default قرار دهید.

بستن یک کلید


زمانی که دیگر با کلید کاری ندارید و می‌خواهید تغییرات در رجیستری ثبت گردد باید فرآیندی به نام
flushing را انجام دهید. برای انجام این کار به راحتی از متد RegistryKey.Close استفاده کنید.
RegistryKey MyReg = Registry .CurrentUser.CreateSubKey( "SOFTWARE\\SomeCompany\\SomeApp\\SomeVer" );
int nSomeVal = ( int )MyReg.GetValue( "SomeVal" , 0);
MyReg.SetValue( "SomeValue" , nSomeVal + 1);
MyReg.Close();

پاک کردن یک کلید

برای پاک کردن یک زیرکلید از متد RegistryKey.DeleteSubKey به دو صورت استفاده می‌کنیم.

public void DeleteSubKey( string subkey);
public void DeleteSubKey( string subkey, bool throwOnMissingSubKey);
در صورت اول زیرکلید subkey را به شرطی حذف می‌کند که زیرکلید مذکور موجود باشد و زیرکلید دیگری در زیر آن نباشد. در صورت دوم نیز این شروط برقرار است با این تفاوت که اگر زیرکلید مذکور یافت نشود و throwOnMissingSubKey مقدار true داشته باشد یک exception فرا می‌خواند.

پاک کردن کل یک درخت


برای پاک کردن کل یک درخت با همه‌ی کلیدهای فرزند و مقادیر آن‌ها از متد
RegistryKey.DeleteSubKeyTree به دو صورت استفاده می‌کنیم.
public void DeleteSubKeyTree( string subkey);
public void DeleteSubKeyTree( string subkey, bool throwOnMissingSubKey);
دیگر با پارامترهای ارسالی در این متد آشنایی دارید و لازم به توضیح نیست.

پاک کردن یک مقدار


برای پاک کردن یک مقدار از متد
RegistryKey.DeleteValue به دو صورت زیر استفاده می‌کنیم.
public void DeleteValue( string name);
public void DeleteValue( string name, bool throwOnMissingValue);

لیست کردن زیرکلیدها

برای به دست آوردن یک لیست از همه زیرکلیدهای یک شیء RegistryKey از متد RegistryKey.GetSubKeyNames به صورت زیر استفاده می‌کنیم که یک آرایه رشته‌ای از نام زیرکلیدها را برمی‌گرداند.

public string [] GetSubKeyNames();
هم چنین می‌توانید برای شمردن تعداد زیرکلیدها از خصوصیت RegistryKey. SubKeyCount استفاده نمایید.

لیست کردن نام مقادیر


برای به دست آوردن یک لیست از همه مقادیری که در یک شیء
RegistryKey وجود دارند از متد RegistryKey.GetValueNames به صورت زیر استفاده می‌کنیم که یک آرایه رشته‌ای از نام مقادیر را برمی‌گرداند.
public string [] GetSubKeyNames();
هم چنین می‌توانید برای شمردن تعداد زیرکلیدها از خصوصیت RegistryKey.ValueCount استفاده نمایید.

ثبت تغییرات به صورت دستی


برای ثبت تغییرات یا به اصطلاح فلاش کردن به صورت دستی می‌توانید از متد
RegistryKey.Flush به صورت زیر استفاده نمایید. زمانی که از RegistryKey.Close استفاده می‌کنید فرآیند فلاش کردن به طور اتوماتیک انجام می‌گیرد.
public void Flush();

مطالب
نحوه استفاده از Text template ها در دات نت - قسمت اول
 یکی از امکانات کمتر شناخته شده در دات نت، امکان تولید اتوماتیک کد (Code Generator)، توسط فایلهایی به عنوان Text template می‌باشد. اگر چه فایلهای Text template با پسوند tt  از Visual Studio 2008 بطور آشکار به IDE اضافه گردیده‌اند، این امکان پیش از این نیز بصورت توکار در Visual Studio جهت تولید کد دات نت برای ابزارهایی مانند Dataset ، Report  و ... وجود داشته است. در حال حاضر Visual Studio بصورت توکار  از این امکان برای تولیدکلاسها و  کد‌های EntityFramework ( edmx ) ،dbml  ، Dataset  و ... استفاده می‌نماید. 
شما نیز با دانستن قواعد ساده کد نویسی برای Text template‌ها می‌توانید از این امکان برای تولید اتوماتیک کلاسها، HTML ، XML  و بطور کلی هر نوع فایل متنی استفاده نمایید. کاربردهای عملی Text template بیشتر برای تولید کد از روی دیتابیس و مثلا بر اساس فیلد‌های هر جدول و امثال آن می‌باشد. اما با کمی خلاقیت استفاده‌های بسیار زیاد و جالبی را می‌توانید از آن مشاهده نمایید.
کاربردهایی مانند : تولید خود کار فایل Config، تولید خودکار  Unit Test، تولید خودکار کلاسهای CRUD برای هر موجودیت در لایه Data، تولید خودکار SQL برای StoredProcedure ها، تولید خودکار Html و Js، تولید خودکار فرمهای ASPX و ... برای فرمهای ثابت و تکراری با فرآیند مشخص، تولید خودکار مستندات پروژه در قالب Word Document  , …  ،  تولید خودکار فایلهای Excel از اطلاعات خاص و تولید خودکار فرمهای xaml و .....

در این آموزش با قواعد اصلی نوشتن کد برای Text templateها آشنا می‌شویم و چند نمونه از کاربردهای آن را به عنوان مثال کاربردی مورد بررسی قرار خواهیم داد.
برای شروع قبل از توضیح در مورد قواعد کد نویسی Text template، یک فایل Text template ایجاد نمایید. برای ایجاد، از پنجره Add New Item  یک فایل Text template به پروژه اضافه نمایید:
 


توجه داشته باشید که نام فایل خروجی دقیقا هم نام با فایل tt مشخص شده خواهد بود. اما پسوند آن بسته به تنظیمات داخل آن متفاوت است. با اضافه کردن Text template داخل فایل، باید کد‌های زیر را مشاهده نمایید؛ در غیر این صورت آن را بنویسید:
 <#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".txt" #>
Language زبانی را مشخص می‌کند که می‌خواهید با آن داخل فایل Text template کد نویسی نمایید. تعیین آن برای کامپایل الزامی است.
Extension نیز پسوند فایل خروجی تولید شده را مشخص می‌نماید . 
اگر در ادامه متن Hello dotnettips را بنویسید و فایل را Save کنید، کنار فایل tt مذکور، یک فایل با همان نام و پسوند txt ایجاد خواهد شد که داخل آن نوشته است:
Hello dotnettips

برای ایجاد فایل خروجی همچنین میتوانید روی فایل tt  کلیک راست نموده و از منوی باز شده  Run Custom Tool  را انتخاب نمایید. توجه داشته باشید که در تنظیمات Custom Tool باید مقدار  TextTemplatingFileGenerator وجود داشته باشد:
 

خوب؛ برای ادامه، باید با قواعد کد نویسی در Text template آشنا شوید. جلسه بعدی قواعد کد نویسی T4  را بررسی خواهیم کرد.

مطالب دوره‌ها
بوت استرپ (نگارش 3) چیست؟
بوت استرپ یک فریم ورک CSS واکنشگرا (responsive) است، که جهت ساخت سریع برنامه‌های استاتیک و همچنین پویای وب کاربرد دارد. در حال حاضر این پروژه جزو محبوب‌ترین و فعال‌ترین پروژه‌های سایت Github است. اگر علاقمند هستید که لیستی از سایت‌های استفاده کننده از بوت استرپ را مشاهده کنید، به آدرس‌های ذیل مراجعه نمائید:


تازه‌های بوت استرپ 3 کدامند؟

- بوت استرپ 3 جهت کار با صفحه‌های نمایش کوچک دستگاه‌های موبایل به شدت بهینه سازی شده است و به همین جهت به آن mobile-first CSS framework نیز می‌گویند.
- در نگارش 2 بوت استرپ، حداقل دو نوع گرید واکنشگرا و غیر واکنشگرا قابل تعریف بودند. در نگارش سوم آن، تنها یک نوع گرید جدید واکنشگرا در این فریم ورک وجود دارد که می‌تواند چهار نوع سایز از بزرگ تا کوچک را شامل شود.
- بوت استرپ 3 با IE7 به قبل و همچنین فایرفاکس 3.6 و پایین‌تر دیگر سازگار نیست. البته برای پشتیبانی از IE8، نیاز به اندکی تغییرات نیز وجود خواهد داشت که در قسمت‌های بعد این جزئیات را بیشتر بررسی خواهیم کرد. به عبارت دیگر بدون این تغییرات، بوت استرپ 3 در حالت پیش فرض با IE9 به بعد سازگار است.
- در بوت استرپ 3 برخلاف نگارش قبلی آن که لیستی از آیکن‌های خود را در قالب چند فایل PNG image sprite که آیکن‌ها را به صورت فشرده در کنار هم قرار داده بود، اینبار تنها از Font icons استفاده می‌کند. به این ترتیب تغییر اندازه این آیکن‌ها با توجه به برداری بودن نمایش قلم‌ها و همچنین قابلیت اعمال رنگ به آن‌ها نیز بسیار ساده‌تر می‌گردد.


سؤال: آیا نیاز است از یک فریم ورک CSS واکنشگرا استفاده شود؟

در سال‌های قبل، عموما طراحی وب بر اساس تهیه یا خرید یک سری قالب‌های از پیش آماده شده، شکیل صورت می‌گرفته‌است. این قالب‌ها به سرعت با برنامه، یکپارچه شده و حداکثر قلم یا رنگ‌های آن‌ها‌را اندکی تغییر می‌دادیم و یا اینکه خودمان کل این مسیر را از صفر طی می‌کردیم. این پروسه سفارشی، بسیار سنگین بوده و مشکل مهم آن، عدم امکان استفاده مجدد از طراحی‌های انجام شده می‌باشد که نهایتا در دراز مدت هزینه‌ی بالایی را برای ما به همراه خواهند داشت. اما با استفاده از فریم ورک‌های CSS واکنشگرا به این مزایا خواهیم رسید:
- قسمت عمده‌ای از کار پیشتر برای شما انجام شده است.
برای مثال نیازی نیست تا حتما برای طرحبندی صفحه، سیستم گرید خاص خودتان را طراحی کنید و یا اینکه مانند سال‌های دور، به استفاده از HTML tables پناه ببرید.
- قابلیت سفارشی سازی بسیار بالایی دارند.
برای مثال با استفاده از فناوری‌هایی مانند less می‌توان بوت استرپ را تا حد بسیار زیادی سفارشی سازی کرد. به این ترتیب دیگر یک سایت بوت استرپ، شبیه به بوت استرپ به نظر نخواهد رسید! شاید عده‌ای عنوان کنند که تمام سایت‌های بوت استرپ یک شکل هستند، اما واقعیت این است که این سایت‌ها تنها از قابلیت‌های سفارشی سازی بوت استرپ و less استفاده نکرده‌اند.
 

دریافت بوت استرپ 3

سایت رسمی دریافت بوت استرپ، آدرس ذیل می‌باشد:

البته ما از این نگارش خام استفاده نخواهیم کرد و نیاز است برای کارهای سایت‌های فارسی، از نگارش راست به چپ آن استفاده کنیم. بنابراین اگر از ویژوال استودیو استفاده می‌کنید، می‌توانید به یکی از دو بسته نیوگت ذیل مراجعه نمائید:
و اگر می‌خواهید صرفا به فایل‌های درون این بسته‌ها دسترسی پیدا کنید، از دو آدرس ذیل استفاده کنید:
فایل‌های دریافت شده با پسوند nupkg، در حقیقت یک فایل zip استاندارد هستند.

اگر بوت استرپ اصل را از سایت اصلی آن دریافت کنید، شامل تعداد فایل‌ها و پوشه‌های بسیار بیشتری است نسبت به نمونه RTL فوق. اما فایل‌های نهایی آن که مورد استفاده قرار خواهند گرفت، درون پوشه dist یا توزیع آن قرار گرفته‌اند و آنچنان تفاوتی با نگارش RTL ندارند. فقط در نگارش اصل، فایل‌های min و فشرده شده نیز همراه این بسته هستند که در نگارش RTL لحاظ نشده‌اند. این موضوع در آینده به نفع ما خواهد بود. از این لحاظ که اگر از سیستم bundling & minification مربوط بهASP.NET  استفاده کنید (جهت تولید خودکار فایل‌های min در زمان اجرا)، این سیستم به صورت پیش فرض از فایل‌های min موجود استفاده می‌کند و ممکن است مدتی سردرگم باشید که چرا تغییراتی را که به فایل CSS بوت استرپ اعمال کرده‌ام، در سایت اعمال نمی‌شوند. به علاوه امکان اعمال تغییرات و حتی دیباگ فایل‌های غیرفشرده خصوصا جاوا اسکریپتی آن نیز بسیار ساده‌تر و مفهوم‌تر است.

جهت مطالعه مباحث تکمیلی در مورد نحوه فشرده سازی فایل‌های CSS یا JS می‌توانید به مقالات ذیل، در سایت جاری مراجعه نمائید:

علاوه بر این‌ها در نگارش سوم بوت استرپ، تعدادی فایل CSS جدید به نام قالب یا theme نیز اضافه شده‌اند که همراه نسخه RTL نیست. برای مثال اگر به پوشه bootstrap-3.0.0.zip\bootstrap-3.0.0\dist\css مراجعه کنید، فایل bootstrap-theme.css نیز قابل مشاهده است. به این ترتیب قالبی و لایه‌ای بر روی مقادیر پیش فرض موجود در فایل bootstrap.css اعمال خواهند شد؛ برای مثال اعمال طراحی تخت یا flat مدرن آن به دکمه‌ها و عناصر دیگر این مجموعه.


شروع یک فایل HTML با بوت استرپ

تا اینجا فرض بر این است که فایل‌های بوت استرپ را دریافت کرده‌اید. در ادامه قصد داریم، نحوه معرفی این فایل‌ها را در یک فایل ساده HTML بررسی کنیم.
<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My Website</title>
    <link href="Content/css/bootstrap-rtl.css" rel="stylesheet">    
<link href="Content/css/custom.css" rel="stylesheet">    
</head>
<body>


</body>
</html>
صفحه آغازین کار با بوت استرپ 3 یک چنین شکلی را خواهد داشت و می‌تواند پایه تشکیل فایل masterpage یا layout برنامه‌های ASP.NET قرار گیرد. متا تگ viewport اضافه شده، جهت طراحی‌های واکنشگرا اضافه شده است و در ادامه لینک شدن فایل CSS بوت استرپ 3 را ملاحظه می‌کنید.
اگر سایت شما از تعاریف CSS سفارشی دیگری نیز استفاده می‌کند، تعاریف آن‌ها باید پس از بوت استرپ، ذکر گردند.


افزودن اسکریپت‌های بوت استرپ 3

برای کار با اسکریپت‌های بوت استرپ 3 نیاز است ابتدا jQuery را به صورت جداگانه دریافت کنیم. در حال حاضر اگر به سایت جی‌کوئری مراجعه کنید با دو نگارش 1.x و 2.x این کتابخانه مواجه خواهید شد. اگر نیاز به پشتیبانی از IE 8 را در محل کار خود دارید، باید از نگارش 1.x استفاده کنید. نگارش آخر 1.x کتابخانه جی‌کوئری را از طریق CDN آن همواره می‌توان مورد استفاده قرار داد:
 <script src="http://code.jquery.com/jquery-latest.min.js"></script>
بهتر است تعاریف فایل‌های جاوا اسکریپت را پیش از بسته شدن تگ body قرار دهید. یکی از مزایای مهم آن مشاهده نشدن یک فلش کوتاه مدت سفید رنگ در ابتدای بارگذاری صفحاتی با پس زمینه غیر روشن است. از این جهت که هر المانی که در head صفحه تعریف شود، حتما باید پیش از بارگذاری کل صفحه دریافت گردد. به این ترتیب با سرعت‌های دریافت کمتر، این مساله سبب خالی ماندن صفحه برای مدتی کوتاه خواهد شد و همان فلش سفید رنگ عنوان شده را پدید می‌آورد؛ چون هنوز مابقی صفحه بارگذاری نشده و خالی است.
پس از تعریف جی‌کوئری، تعریف اسکریپت‌های بوت استرپ قرار می‌گیرد (چون وابسته است به جی‌کوئری). فایل bootstrap-rtl.js شامل تمام زیر فایل‌های مورد نیاز نیز می‌باشد:
 <script src="Scripts/bootstrap-rtl.js"></script>
برای سازگار سازی بوت استرپ 3 با IE8 نیاز به یک فایل اسکریپت دیگر نیز داریم. این فایل را از آدرس ذیل دریافت نمائید:
این فایل 4 کیلوبایتی را نیز باید به تعاریف اسکریپت‌های مورد نیاز، اضافه کرد:
 <script src="Scripts/respond.min.js"></script>
البته این اسکریپت خاص، مطابق توضیحات آن باید به head صفحه اضافه شود تا با IE8 بهتر کار کند.
تا اینجا ساختار صفحه HTML تهیه شده جهت استفاده از امکانات بوت استرپ 3، شکل زیر را خواهد داشت:
<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My Website</title>

    <link href="Content/css/bootstrap-rtl.css" rel="stylesheet">    
<link href="Content/css/custom.css" rel="stylesheet">       
<script src="Scripts/respond.min.js"></script>
</head>
<body>


<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script src="Scripts/bootstrap-rtl.js"></script>
</body>
</html>

فایل‌های نهایی این قسمت را از اینجا نیز می‌توانید دریافت کنید:
bs3-sample01.zip
 
نظرسنجی‌ها
اگر بخواهید کنار دات نت بر روی یک پلتفرم یا زبان دیگری نیز کار کنید کدام را انتخاب می کنید؟
زبان جاوا اسکریپت و پلتفرم node.js
زبان پایتون و کار بر روی فریم‌ورکهای مختلف آن
زبان جاوا
php
دیگر زبانها
Go-Lang
Ruby و پلتفرمهایش
زبان سی پلاس پلاس در محیطهای محتلف مثل visual c++ یا QT
مطالب
فقط به خاطر یک نیم فاصله!
نسخه‌ی 64 بیتی ویندوز 7 را نصب کرده‌ام و اولین مشکل، نبود صفحه کلید مطابق استاندارد 2091 برای نسخه‌های 64 بیتی ویندوز است. پروژه وب فارسی دانشگاه صنعتی شریف، سال‌ها قبل فقط یک نسخه‌ی 32 بیتی از آن را تهیه کرده و نسخه‌های 64 بیتی موجود، مطابق استاندارد 9147 هستند و من به دلایل ذیل حاضر به استفاده از آن نیستم!
  1. در استاندارد 9147 ، جای ژ و پ مطابق صفحه کلیدی که در بازار ایران فروخته می‌شود نیست (و باید به همه پاسخگو باشید که چرا اینطوری است).
  2. ی و ک در آن اصلاح شده و دیگر عربی نیست که چقدر هم خوب، اما من تعداد زیادی برنامه و همچنین تعداد قابل توجهی فایل word دارم که مطابق استاندارد 2091 تهیه شده‌اند. مشکلات ی و ک فارسی و عربی را هم در اینجا ذکر کرده‌ام و به دنبال باگ‌های جدید در برنامه‌ها نمی‌گردم.
  3. با ی و ک فارسی اگر در گوگل جستجو کنید تعداد پاسخ‌های مرتبط یافت شده بسیار بسیار کمتر از حالتی خواهد بود که با ی و ک عربی جستجو کنید.
  4. در یک سازمان باید رویه‌ا‌ی واحد در این مورد برقرار باشد. یا همه باید از 2091 استفاده کنند و یا همه از 9147.

نسخه‌ی کامل استاندارد 9147 را از سایت آقای اخگری می‌توانید دریافت نمائید:

به همین دلایل خصوصا قسمت دوم (هر چند ممکن است با آن موافق نباشید)، نیاز به صفحه کلید مطابق استاندارد 2091 نسخه‌ی 64 بیتی داشتم.

برای تهیه صفحه کلید فارسی از برنامه Microsoft Keyboard Layout Creator استفاده می‌شود که نسخه‌ی 1.4 آن‌را از آدرس زیر می‌توانید دریافت نمائید. این نسخه قابلیت تولید فایل‌های dll مرتبط 64 بیتی را هم دارد:


یکی از قابلیت‌های این برنامه بارگذاری صفحه کلید فارسی جاری سیستم است:



صفحه کلید استاندارد 2091 پروژه وب فارسی را اگر با آن باز کرده و سپس از منوی Project گزینه‌ی Build DLL and setup package را انتخاب نمائید، با خطای زیر متوقف خواهید شد:
ERROR: 'VK_SPACE' in Shift State 'Shift' must be made up of white space character(s), but is defined as '‌' (U+200c) instead.
که دقیقا مربوطه به این سطر در تعاریف صفحه کلید است (صفحه کلید را می‌شود به صورت فایلی با پسوند klc هم save as کرد):
39 SPACE  0 0020 200c 0020 -1  // SPACE, ZERO WIDTH NON-JOINER, SPACE, <none>
مفاهیم این ستون‌ها هم به شرح زیر هستند:
0 //Column 4
1 //Column 5 : Shft
2 //Column 6 :       Ctrl
3 //Column 7 : Shft  Ctrl
یعنی جهت نمایش نیم فاصله حاصل از ترکیب shift space مطابق استاندارد تایپ ایران، بجای 0x0020 یا همان فاصله، از 0x200C استفاده شده است (مطابق استاندارد تایپ ایران باید نوشت "می‌روم" و نه "می روم". به نیم فاصله و فاصله دقت بفرمائید).
اما این برنامه‌ی محترم دقیقا همین مورد را غلط گرفته و فایل dll نهایی را تولید نمی‌کند (مطابق خطایی که ذکر شد).
برنامه‌ی Microsoft Keyboard Layout Creator هم با دات نت فریم ورک نوشته شده است. اگر کمی با reflector به آنالیز آن بپردازیم به کلاس Accept و متد زیر خواهیم رسید:
private bool VerifySpaceBarIntegrity(ShiftState ss, bool fMustBeDefined)
در این متد جایی که خطای ذکر شده صادر می‌شود، مربوط به چند سطر زیر است:
if (!Utilities.IsSpacing(ss.Characters))
{
    this.WriteErrorToLogFile("SpaceKeyNeedsWhiteSpaceCharacters", new string[] { "VK_" + Utilities.VkStringOfIvk(ss.VK), this.m_stStateLabel[ss.State], ss.Characters, Utilities.FromCharacterToUPlusForm(ss.Characters) });
    flag = false; /*اینجا باید اصلاح شود!*/
}
خوب! به نظر شما ایرادی دارد که این flag همیشه true باشد؟! برای همین منظور، فایل MSKLC.exe را پچ کرده‌ام که از آدرس زیر قابل دریافت است:

  دریافت پچ شده نگارش 1.4.6000.2 : MSKLC.Patched.7z  

با استفاده از این نسخه (ابتدا برنامه اصلی را نصب کرده و سپس فایل exe را جایگزین نمائید)، به راحتی می‌توان نسخه‌ی استاندارد و اصلی 2091 را بارگذاری و مجددا کامپایل کرد (بدون توقف کامپایل به خاطر فقط یک نیم فاصله‌ی غیرمعتبر از دیدگاه نویسندگان اصلی برنامه). به این صورت فایل‌های 64 بیتی لازم هم تولید می‌شوند ( ممکن است در حین کار با برنامه‌ی patch شده، نمایش خطای کار با نیم فاصله را مجددا دریافت کنید؛ اما مهم نیست . نمونه‌ی وصله شده، بدون مشکل حاصل را کامپایل می‌کند که در نمونه‌ی اصلی اینطور نیست. یعنی پس از overwrite کردن فایل exe موجود، با نمونه patch شده، برنامه کار کامپایل را کامل می‌کند) که حاصل نهایی را از آدرس زیر می‌توانید دریافت نمائید:


این فایل‌ها دقیقا بر مبنای همان فایل‌های پروژه وب فارسی استاندارد 2091 هستند؛ با این تفاوت که نسخه‌‌های غیر 32 بیتی هم در آن لحاظ شده‌اند.

نصب این dll‌ها هم از ویندوز ویستا به بعد داستان خودش را پیدا کرده؛ ابتدا باید take ownership شود، سپس می‌توان فایل اصلی را به سادگی جایگزین کرد و سپس reboot .
برای این منظور ابتدا به پوشه‌ی system32 ویندوز مراجعه کرده و فایل KBDFA.DLL را پیدا کنید.
در ادامه به پنجره خواص آن (کلیک راست و انتخاب properties) مراجعه و برگه‌ی Security آن‌را انتخاب کنید.
در این قسمت بر روی دکمه‌ی Advanced کلیک نمائید.
در صفحه‌ی باز شده به برگه‌ی Owner مراجعه کنید.
در این قسمت بر روی دکمه‌ی Edit کلیک نموده و کاربر خودتان را اضافه نمائید.
پس از طی این مرحله (یا همان take ownership) به برگه security مراجعه کرده و به کاربر خودتان دسترسی full control بدهید.
اکنون مجوز تغییر این فایل را بدون هیچ مشکلی خواهید یافت.
در پایان reboot را فراموش نکنید.

راه دوم:
یا برنامه نصاب حاصل از برنامه‌ی Microsoft Keyboard Layout Creator، مدخل جدیدی را به صفحه کلیدهای قابل انتخاب ویندوز در کنترل پنل اضافه می‌کند که نیازی به reboot ندارد.
مطالب
babel چیست؟ lebab چیست؟
قطعا به عنوان برنامه نویس JavaScript کم و بیش با ecmaScript 6 آشنایی دارید.
با وجود ویژگی‌های منحصر به فردی که دارد شاید تنها دلیلی که برخی از برنامه نویسان هنوز تصمیم به عدم استفاده از این زبان را دارند، مرورگرهایی میباشند که هنوز از es6 پشتیبانی نمیکنند: es6 compatibility table 
اما راهکاری مناسب، برای اینکه بتوان هم از es6 استفاده کرد و هم کاربران را مجبور به استفاده‌ی از مرورگر‌های مدرن نکنیم نیز وجود دارد:به صورت مستقیم میتوان با استفاده از Babel، کد‌های نوشته شده‌ی با es6 را کامپایل و تبدیل به es5 کنیم. برای اینکار معمولا از gulp استفاده میکنیم. 
gulp در وبسایت رسمی آن، خودش را اینچنین تعریف کرده است : automate and enhance your workflow
حال کافیست با چند خط کد es6 شروع به کار کنیم. بنده معمولا از visual studio code استفاده میکنم.
class firstCLs
{
    doFirst(str)
    {
        console.log(str);
    }
}

class secondCls extends firstCLs
{
    doSecond(str)
    {
        super.doFirst(str);
    }
}

let str = 'string';
new secondCls().doSecond(`this is some ${str}`);
فکر میکنم کد‌های فوق احتیاج به توضیح بیشتری نداشته باشند. اکنون فرض کنید نام فایل آن code.js است و در پوشه‌ی src قرار دارد. همانطور که پیشتر عرض کردم، برای تبدیل آن به کدی از نوع es5 از gulp استفاده می‌کنیم.
ابتدا از طریق خط فرمان، خود gulp را نصب میکنیم. 
npm install -g gulp
بعد بر روی پوشه‌ی root پروژه‌تان رفته و با استفاده از خط فرمان، npm init را ارسال کنید تا package.json برای شما ساخته شود.
برای نصب gulp در پروژه‌ی local خود نیز این فرمان را ارسال کنید:
npm install gulp --save-dev
با استفاده از این فرمان، gulp را در مسیر جاری پروژه‌تان و در پوشه‌ی node-modules نصب کرده و همچنین فرمان --save-dev نیز آن را به وابستگی‌های پروژه اضافه میکند.
حال احتیاج به نصب gulp-babel داریم که با استفاده از خط فرمان، خود آن را نصب مینماییم:
npm install --save-dev gulp-babel babel-preset-es2015
حال در مسیر اصلی پروژه، فایل gulpfile.js را ساخته و کدهای زیر را مینویسیم:
const gulp = require('gulp');
const babel = require('gulp-babel');
 
gulp.task('default', () => {
return gulp.src('src/code.js')
.pipe(babel({
presets: ['es2015']
}))
.pipe(gulp.dest('dist'));
});
برای توضیح کد‌های بالا باید عرض کنم در قسمت gulp.task، عملیاتی را که لازم میدانیم gulp برای ما انجام دهد، شرح میدهیم.
gulp.src مسیر فایلی را که تصمیم داریم کامپایل شده و به es5 تبدیل شود، معین می‌کند ( لازم به ذکر است که میتوان بطور مثال همه‌ی اسکریپت‌های درون یک پوشه را انتخاب کرد که توضیح آن در این مقاله نمیگنجد).
بعد در قسمت اولین pipe فوق است که میخواهیم تبدیلی را به es2015 داشته باشیم و در آخرین pipe نیز با استفاده از متد dest، آدرس مسیری را که میخواهیم آن فایل کامپایل شده در آن قرار بگیرد، مینویسیم. بطور مثال من پوشه‌ی dist را به عنوان آدرس قرار داده‌ام.
مراحل انجام شده را save نمایید. خط فرمان خود را باز کرده و دستور gulp را type نمایید. بعد از پایان یافتن عملیات، به پوشه‌ی dist رجوع کنید. فایل مورد نظر مشاهد میشود.

اما حال فرض کنید پروژه ای در اختیار داشته و کد‌ها از نوع es5 میباشند و تصمیم به تبدیل آن‌ها به es6 داشته باشید.
برای اینکار از lebab (که دقیقا عکس نوشتاری bable میباشد) استفاده میکنیم.
ابتدا از طریق خط فرمان خود آن را نصب مینماییم
npm install -g lebab
به صورت مستقیم میتوانیم هر فایلی را که به صورت استاندارد نوشته شده است، کامپایل کرده و تبدیل به es6 نماییم.
کد‌های زیر را در نظر بگیرید
'use strict';

// Let/const
var name = 'Bob', time = 'yesterday';
time = 'today';

// Template string
console.log('Hello ' + name + ', how are you ' + time + '?');

var bob = {
  // Object shorthand
  name: name,
  // Object method
  sayMyName: function () {
    console.log(this.name);
  }
};

// Classes
var SkinnedMesh = function SkinnedMesh() {
};

SkinnedMesh.prototype.update = function (camera) {
  camera = camera || createCamera();
  this.camera = camera;
};

Object.defineProperty(SkinnedMesh.prototype, 'name', {
  set: function (geometry) {
    this.geometry = geometry;
  },
  get: function () {
    return this.geometry;
  }
});

// Commonjs
var lebab = require('lebab');
module.exports = SkinnedMesh;

// Arrow functions
var render = function () {
  // ...
  requestAnimationFrame(render);
};
فرض کنید آن را با نام es5.js در مسیر اصلی پروژه ذخیره کرده‌ایم. با استفاده از خط فرمان خود آن را تبدیل به es6 خواهیم کرد؛ بدین شکل:
lebab es5.js -o es6.js
فایل مورد نظر ما به نام es6.js ذخیره خواهد شد و بدین صورت کامپایل خواهد شد
const name = 'Bob';
let time = 'yesterday';
time = 'today';

// Template string
console.log(`Hello ${name}, how are you ${time}?`);

const bob = {
  // Object shorthand
  name,
  // Object method
  sayMyName() {
    console.log(this.name);
  }
};

class SkinnedMesh {
  update(camera=createCamera()) {
    this.camera = camera;
  }

  set name(geometry) {
    this.geometry = geometry;
  }

  get name() {
    return this.geometry;
  }
}

import lebab from 'lebab';
export default SkinnedMesh;

// Arrow functions
const render = () => {
  // ...
  requestAnimationFrame(render);
};
تبدیل es5 به es6 انجام شد؛ اما باید خدمتتان عرض کنم آنچنان هم نباید انتظار داشت که بعد از این تبدیل و فشار دادن دکمه‌ی F5، پروژه‌ی شما بدون هیچ خطایی اجرا شود (البته در صورتیکه هنوز در اوایل پروژه هستید شاید اینگونه شود) اما کمی refactoring برای کد‌های کامپایل شده را به es 6، در خاطر داشته باشید.
مطالب
مقایسه و بررسی پوشه‌های Bin و Obj در برنامه‌های NET.
زمانیکه شما یک برنامه‌ی دات نتی نوشته شده به زبان سی شارپ را کامپایل می‌کنید، دو پوشه‌ی bin و obj را مشاهده می‌کنید. در این مطلب، اهمیت و تفاوت این دو پوشه را بررسی می‌کنیم. این پوشه‌ها حاوی کد‌های کامپایل شده‌ی IL می‌باشند. 

فرآیند کامپایل به دو مرحله‌ی کامپایل سورس کد و همچنین ایجاد پیوند (linking) بین فایل‌های کامپایل شده تقسیم می‌شود.
به دیاگرام زیر دقت نمائید:
• در مرحله‌ی کامپایل، هر یک از سورس فایل‌ها، بصورت مجزا کامپایل می‌شود و به ازای هر سورس فایل، یک فایل مجزای کامپایل شده تولید می‌شود. بدین معنا که اگر دو فایل داشته باشیم، دو کد مستقل کامپایل شده نیز تولید می‌شوند.
• در مرحله‌ی متصل کردن (linking)، همه‌ی فایل‌های کامپایل شده به یک اسمبلی واحد کامپایل می‌شوند که این اسمبلی می‌تواند از نوع DLL و یا EXE باشد.

اگر هر دو پوشه را مقایسه کنید، تعداد فایل‌های موجود در obj، بیشتر از bin است؛ به این خاطر که در این پوشه برای هر فایل، یک فایل کامپایل شده‌ی مجزا تولید می‌شود.

اما سؤالی که در ذهن ایجاد می‌شود این است که چرا این فرآیند در دو مرحله انجام می‌شود و چرا فرآیند کامپایل در یک مرحله انجام نمی‌شود. با انجام 2 مرحله‌ای فرآیند کامپایل، می‌توان از قابلیت کامپایل شرطی (Conditional Compiling) بهره‌مند شد.
زمانیکه یک پروژه‌ی بزرگ را کامپایل می‌کنیم، انتظار داریم تنها فایل‌هایی را که تغییر کرده‌اند، کامپایل شوند و در پوشه‌ی obj، ما هر فایل کامپایل شده را بصورت مجزا داریم. در نتیجه می‌توانیم تشخیص دهیم  که چه فایل‌هایی تغییر کرده‌اند و تنها آنها را کامپایل می‌کنیم که این کار باعث افزایش سرعت فرآیند کامپایل می‌شود.

بطور خلاصه در پوشه‌ی obj، ما به ازای هر سورس فایل، یک فایل کامپایل شده داریم؛ اما در پوشه‌ی bin تنها یک فایل یکپارچه شده را خواهیم داشت.