Constant Field : فیلد ثابتی که مستقیما در یک Class و یا Struct تعریف میشود.
Constant Local : ثابتی که در بلاکهای برنامه (بدنه یک تابع ، حلقه تکرار و ...) تعریف میشود.
جدول مقایسهای بین Const و ReadOnly
Constant | ReadOnly |
میتواند به Fieldها و همچنین localها اعمال شود. | تنها به Field ها اعمال میشود. |
مقدار دهی اولیه آن الزامی است. | مقدار دهی اولیه میتواند هنگام تعریف و یا در درون سازنده انجام شود (در هیچ متد دیگری امکان پذیر نیست). |
تخصیص حافظه انجام نمیشود و مقدار آن در کدهای IL گنجانده میشود (توضیح در ادامه مطلب). | تخصیص حافظه بصورت داینامیک انجام میشود و میتوانیم در زمان اجرا مقدار آن را بدست آوریم. |
ثابتها در #C بصورت پیش فرض از نوع static هستند. بدین معنا که از طریق نام کلاس قابل دسترسی هستند. | تنها از طریق وهله سازی از یک کلاس قابل دسترسی هستند. |
نوعهای درون ساز (built in) و Null Reference ها را میتوان بصورت const تعریف کرد. Boolean,Char, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Decimal , string. | مشابه Constant ها |
مقدار آن در طول عمر یک برنامه ثابت است. | مقدار آن میتواند در هنگام فراخوانی سازنده برای وهلههای مختلف متفاوت باشد. |
فیلدهای const را نمیتوان بصورت پارامترهای out و ref استفاده کرد. | فیلدهای ReadOnly را میتوان بصورت پارامترهای ref و out در درون سازنده استفاده کرد. |
نحوه تعریف یک constant :
همانطور که در تصویر مشاهده میکنید در کنار نماد انتخابی برای constها یک قفل کوچک (نشان از غیرقابل تغییر بودن) قرار گرفته است .
مثالی از تعریف و رفتار Constantها در #C :
const int field_constant = 10; //constant field static void Main(string[] args) { const int x = 10, y = 15; //constant local :correct const int z = x + y; //constant local : correct; const int a = x + GetVariableValue();//Error } public static int GetVariableValue() { const int localx = 10; return 10; }
فیلدهای فقط خواندنی ReadOnly
در #C فقط Fieldها را میتوان بصورت ReadOnly تعریف کرد. این فیلدها یا در زمان تعریف و یا از طریق سازنده مقدار دهی میشوند.
بررسی تفاوت readonly و const در سطح IL
برای مشاهده کدهای سطح میانی (IL Code) از ابزار خط فرمان Developer Command ویژوال استدیو 2017 و همچنین برنامه ILdasm استفاده شده است. همانطور که در جدول مقایسهای بیان شد، برای constant field ها تخصیص حافظهای صورت نمیگیرد و مقادیر مستقیما در کدهای IL گنجانده میشود.
مثال:
class Program { public const int numberOfDays = 7; public readonly double piValue = 3.14; static void Main(string[] args) { } }
ولی مقدار ذخیره شده در piValue در زمان اجرا قابل دسترسی میباشد.
مشکل Versioning فیلدهای const
public const int numberOfDays = 7; public readonly double piValue = 3.14;
کد برنامه اصلی که ارجاعی به اسمبلی جانبی دارد:
static void Main(string[] args) { var readEx = new MyLib.TestClass(); var readConstValue = MyLib.TestClass.numberOfDays; var readReadOnlyValue = readEx.piValue; }
.method private hidebysig static void Main(string[] args) cil managed { .entrypoint // Code size 17 (0x11) .maxstack 1 .locals init ([0] class [MyLib]MyLib.TestClass readEx, [1] int32 readConstValue, [2] float64 readOnlyValue) IL_0000: nop IL_0001: newobj instance void [MyLib]MyLib.TestClass::.ctor() IL_0006: stloc.0 //readEx IL_0007: ldc.i4.7 //ارزش ذخیره شده در کد IL_0008: stloc.1 //readConstValue IL_0009: ldloc.0 //readEg IL_000a: ldfld float64 [MyLib]MyLib.TestClass::piValue IL_000f: stloc.2 //readReadOnlyValue IL_0010: ret } // end of method Program::Main
اگر در کتابخانه جانبی ارزش فیلد const را تغییر دهید و آن را مجدد کامپایل کنید، تا زمانیکه اسمبلی برنامه اصلی را کامپایل نکردهاید، همان ارزش قبلی در برنامه نمایش داده میشود.
برای غلبه بر این مشکل از فیلدهای Static ReadOnly استفاده میکنیم.
مثال:
public class ReadonlyStatic { public static readonly string x = "Hi"; public static readonly string y; public ReadonlyStatic() { //y = "Hello"; This is wrong } static ReadonlyStatic() { y = "Hello"; } }
اولین مشکلی که با استفاده از فیلدهای Static ReadOnly حل میشود، مشکل Versioning فیلدهای Const است. بدین ترتیب دیگر نیازی به کامپایل مجدد برنامه مصرف کننده نیست .
نکته بعدی که در کد فوق نشان داده شدهاست، فیلدهای static readOnly در زمان تعریف و یا تنها از طریق سازندهی static میتوانند مقدار دهی شوند.
مقایسه ReadOnly و Static :
ReadOnly | Static |
هم در زمان تعریف و هم از طریق سازنده میتوان آن را مقدار دهی کرد. | در زمان تعریف و تنها از طریق سازنده static میتوان آن را مقدار دهی کرد. |
مقدار بر اساس مقادیری که در سازندهها تعیین میشود متفاوت است. | مقادیر بعد از مقدار دهی اولیه تغییر نمیکنند. |
چه زمانی از Const و چه زمانی از ReadOnly استفاده کنیم :
- زمانی باید از Const استفاده کرد که مطمئن هستیم ارزش ذخیره شده در آن در طول عمر یک برنامه تغییر نمیکند. بطور مثال ذخیره تعداد روز هفته در یک فیلد از نوع Constant. اگر شک داریم که ممکن است این ارزش تغییر کند، میتوانیم از حالت static readOnly برای غلبه بر مشکل Versioning استفاده کنیم.
- از آنجائیکه مقادیر constant در کدهای IL گنجانده میشوند، برای رسیدن به کارآیی بهتر، مقادیری را که در طول عمر یک برنامه تغییر نمیکنند، به صورت const تعریف میکنیم.
- هر زمان تصمیم داشتیم Constant هایی به ازای هر وهله از کلاس داشته باشیم از ReadOnly استفاده میکنیم.
بوهای کد: جهش
حتی یک مطلب کوچولو هم برای آن آماده کرده و در سیستم اتوماتیک وبلاگم برای انتشار گذاشتهام.
نحوه استفاده از این کامپوننت به این شکل هست:
1- تعریف ستونها:
const columns = [ { field: "fullname", headerName: "First & last Name", description: "name of user", width: 50, }, { field: "age", headerName: "Age", description: "age of user", width: 50, renderCell:(info)=><strong>Age is : {info.data.age}</strong> } ]
2- تعریف استیتهای لازم برا ست کردن سطر ها، لودر، تعداد کل, شماره صفحه و بزرگی هر صفحه(دقت شود که امکان استفاده بدون پیجینگ هم وجود دارد و امکانات کامل را در لینک لایبرری میتوانید مطالعه نمایید)
... const [rows,setRows] = useState([]); const [loading,setLoading] = useState(false); const [totalCount,setTotalCount] = useState(0);
const [filter,setFilter] = useState({ pageSize:10, pageNumber:1 });
const _fetchData = async () => { if (!active) return; //mock api, you can call your api then set data to table like commented line below return new Promise((resolve) => { setLoading(true); setTimeout(() => { setRows(data);// SetRows, note that data comes from api and must be array of objects setTotalCount(7);//=== set total page size for pagination part resolve(); setLoading(false); }, 2000); }); }
import Angrid from "rect-angrid"; ... _handlePageChange = (newPage)=>{ setFilter(p=>({...p,pageNumber:newPage})) } ... <AnGrid loading={loading} columns={columns} rows={rows} showRowNumber={true} pageSize={filter.pageSize} pageNumber={filter.pageNumber} totalCount={totalCount} onPageChange={_handlePageChange} theme="dark" minHeight={300} emptyList={<strong>There Is No Info</strong>} />
سرویس های gRPC در ASP.NET Core
Originally developed at Google, gRPC today is a remote procedure call (RPC) framework that has emerged as an alternative to RESTful and HTTP-based interfaces to connect remote components and specifically microservices. The new RPC framework was created in part to work with modern technologies such as HTTP/2 and Protobuf.
پیشنیازهای این سری
در این سری از بانک اطلاعاتی استاندارد مثال به همراه 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 زمانیکه یک کوئری را اجرا میکند، اطلاعاتی را نیز به همراه آن تولید خواهد کرد که سبب ایجاد یک 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
اینجا است که نیاز به اطلاعات بیشتری در مورد نحوهی اجرای این کوئری داریم. برای استخراج این اطلاعات، اینبار گزینههای تولید و جمع آوری اطلاعات آماری 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
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.
استخراج اطلاعات 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
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.
اگر بر روی این 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
استخراج اطلاعات 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
همانطور که مشاهده میکنید، اینبار نتیجهی حاصل، به همراه اطلاعاتی مانند 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
در اینجا مشخص میشود که آیا عملیات 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
در اینجا حداکثر 10 کوئری را میتوان با هم مقایسه کرد و بیشتر از آن سبب حذف موارد قدیمی از لیست میشود.
عدم نمایش ردیفهای بازگشت داده شدهی توسط کوئری در حین جمع آوری اطلاعات آماری
هربار اجرای یک کوئری در management studio، به همراه بازگشت و نمایش ردیفهای مرتبط با آن کوئری نیز میباشد. اگر میخواهید در حین بررسی کارآیی کوئریها از نمایش این ردیفها صرف نظر کنید (تا بار این برنامه کاهش یابد)، میتوانید از منوی Query، گزینهی Query Options را انتخاب کرده و در قسمت Results، گزینهی Grid آن، گزینهی discard results after execution را انتخاب کنید تا دیگر برگهی results نمایش داده نشود و وقت و منابع را تلف نکند. بدیهی است پس از پایان کار بررسی آماری، نیاز به عدم انتخاب این گزینه خواهد بود.
I can tell at least that in 3 years, JavaScript will gain more the status of a VM and lose the status of a language. Already today, not many people use raw JavaScript. You usually have some transpilation, at least e.g. Babel. In the future, Web Assembly will enable more innovation in that regards, and existing transpiling languages like Elm, TypeScript, PureScript will continue to improve.
یادگیری SASS در 15 دقیقه
If you write copious amounts of CSS, a pre-processor can greatly decrease your stress levels and save you a lot of precious time. Using tools such as Sass, Less, Stylus or PostCSS makes large and complicated stylesheets clearer to understand and easier to maintain. Thanks to features like variables, functions and mixins the code becomes more organized, allowing developers to work quicker and make less mistakes.