- An error occurred while generating the SSH keys. Please check that the environment is properly configured. Details: cat: /Users/cc/Library/Caches/Xamarin/XMA/Keys/1984b83a-dde9-4031-919d-b1d1b8411d0d: No such file or directory
- InvalidOperationException while debugging Xamarin Forms app
- Frame note in module in Xamarin Forms Android
- Internal compiler error is fixed and analysis for WDK completes as usual.
- We fixed an issue in the new Find in Files experience where hidden files and auto-generated files were not searchable.
- Fixed issue with deployment of UWP apps to remote machines where deployment fails with message "DEP0600: Deployment failed. DkmException - Error in the application."
- Local static variable not initialized in inlined function of class imported from dll
- VS 2019 16.5.X: Multiple startup projects while Live Visual Tree was last opened in a debug session crashes
- Fixed issues where for the C++ formatting indentation of new lines with only ending parenthesis.
- Fixed a bug preventing some users from installing 16.5
- Fix an issue where Visual Studio can crash when the display configuration changes.
- Fixed an issue causing slow downs when opening solutions that are impacting the IntelliSense code and related operations.
- Fixed a crash with the debugger that users can run into when the target application being debugged raises an exception.
- Added support for Xcode 11.4.
واژهی کلیدی جدید required در C# 11.0، همانند خواص init-only که پیشتر معرفی شدند، با هدف آغاز و نمونه سازی دقیقتر و سادهتر اشیایی است که برای اینکار، به تعاریف ویژهی سازندهی کلاسها وابسته نیستند.
امکان نمونه سازی بدون قید و شرط کلاسها
تعریف کلاس Article1 را به صورت زیر درنظر بگیرید:
ساختار پروژههای دات نت 7 نیز به صورت پیشفرض به صورت زیر است:
یعنی nullable reference types در آنها فعال است. با این فعال بودن، به اخطارهای زیر میرسیم:
عنوان میکند که خاصیتهای Title و Author، به صورت غیرنالپذیر تعریف شدهاند (و همانند Subtitle نالپذیر نیستند)؛ اما تعریف این کلاس به نحوی است که این مساله را الزامی نمیکند. یعنی میتوان نمونهای از Article1 را ایجاد کرد که در آن، هر دوی این خواص نال باشند؛ هرچند در این حالت مشکلی از لحاظ کامپایل وجود نخواهد داشت، اما ممکن است به علت اشتباه استفادهی از آنها، به null reference exceptions برسیم. چون یکی از مهمترین اهداف استفاده از یک چنین تعاریفی و فعال سازی nullable reference type در یک پروژه، ارائهی متادیتای بهتری جهت خواص و پارامترها و خروجیهای متدهاست تا استفاده کننده دقیقا بداند که آیا این خواص میتوانند نال باشد یا خیر. اگر public string ای تعریف شده، یعنی این خاصیت قطعا نال نخواهد بود و میتوان بدون مشکل و بدون بررسی مقدار آن، از آن استفاده کرد و اگر ?public string ای تعریف شده، یعنی ممکن است مقدار آن نال نیز باشد و بهتر است پیش از استفادهی از آن، حتما مقدار آن بررسی شود. اکنون مشکل اینجا است که هیچگونه قیدی، جهت اجبار به مقدار دهی خواص غیرنال پذیر در اینجا وجود ندارند و میتوان نمونهای از شیء Article1 را ایجاد کرد که در آن متادیتای خواص غیرنال پذیر تعریفی در آن، نقض شوند.
مدیریت کردن نحوهی نمونه سازی کلاسها، با وابستگی به سازندههای آن
یکی از روشهای مدیریت مشکلی که تا اینجا بررسی شد، تعریف سازندههای متعددی برای یک کلاس است؛ تا توسط آن بتوان مقدار دهی یک سری از خواص را اجباری کرد:
در این کلاس، نمونهی بهبود یافتهی Article1 را مشاهده میکنید که استفاده کننده را وادار به مقدار دهی title و author میکند. در این حالت اخطارهای کامپایلری را که مشاهده کردید، رفع میشوند؛ اما به همراه این مسایل است:
- تعداد سطرهای تعریف این کلاس، به شدت افزایش یافتهاست.
- با اضافه شدن خواص بیشتری به کلاس، به تعاریف بیشتری نیاز خواهد بود.
- سازندهها کار خاصی را بجز نگاشت مقادیر ارائه شده، به خواص کلاس، انجام نمیدهند.
- نمونه سازی این کلاسها، شکل طولانی و غیرواضح زیر را پیدا میکند و زیبایی inline object initializers را ندارند:
البته روش دیگر مدیریت یک چنین اخطارهایی، استفاده از مقدار ویژهی !default است که سبب محو اخطارهای یاد شده میشود؛ اما باز هم مقدار دهی آنرا الزامی نمیکند. فقط به این معنا است که قول میدهیم این خاصیت را در جای دیگری مقدار دهی کنیم و هیچگاه نال نباشد!
مدیریت کردن نحوهی نمونه سازی کلاسها، بدون وابستگی به سازندههای آن در C# 11.0
C# 11 به همراه واژهی کلیدی جدیدی به نام required است تا دیگر نیازی نباشد همانند راه حل فوق، سازندههای متعددی را جهت اجبار به مقدار دهی خواص یک شیء، تعریف کنیم. در این حالت تعریف کلاس Article به صورت زیر خلاصه میشود و دیگر به همراه اخطارهای کامپایلر نمایش داده شده نیز نیست:
به این ترتیب هنوز میتوان از زیبایی و خوانایی به همراه نمونه سازی توسط روش inline object initializers بهرهمند شد و همچنین مطمئن بود که اگر استفاده کننده خاصیت غیرنالپذیر Title را مقدار دهی نکند، اینبار با یک خطای کامپایلر متوقف خواهد شد:
معرفی ویژگی جدید SetsRequiredMembers
کلاس Book زیر را که به همراه یک خاصیت required و دو سازندهاست، درنظر بگیرید:
اکنون فرض کنید که بر این اساس، شیءای را به صورت زیر نمونه سازی کردهایم:
این قطعه کد با خطای زیر کامپایل نمیشود:
عنوان میکند که باید خاصیت Name را حتما مقدار دهی کرد؛ چون از نوع required است. هرچند سازندهای که از آن استفاده شده، این مقدار دهی را انجام دادهاست و مشکلی از لحاظ عدم مقدار دهی خاصیت Name در اینجا وجود ندارد. برای رفع این مشکل، باید تغییر زیر را اعمال کرد:
با استفاده از ویژگی جدید SetsRequiredMembers عنوان میکنیم که این سازندهی خاص، حتما خواص از نوع required را نیز مقدار دهی میکند و نیازی به صدور خطای یاد شده نیست. در این حالت بررسی خواص required توسط کامپایلر غیرفعال میشود.
محدودیتهای کار با خواص required
- واژهی کلیدی required را میتوان تنها به خواص و فیلدهای نوعهای class, record, record struct اعمال کرد. امکان اعمال این واژهی کلیدی به اجزای یک اینترفیس وجود ندارد.
- میدان دید اعضای required باید حداقل در حد نوعهای دربرگیرندهی آنها باشند. برای مثال اگر کلاسی public است، نمیتوان در آن یک فیلد required با میدان دید protected را تعریف کرد.
- نوعهای مشتق شدهی از یک نوع پایه، نمیتوانند اعضای required آنرا مخفی کنند و اگر قصد بازنویسی آنرا دارند، باید حتما واژهی کلیدی required را لحاظ کنند.
- اگر سازندهای به سازندهی دیگری از طریق ذکر ()base و یا ()this زنجیر شده باشد نیز باید ویژگی SetsRequiredMembers مرتبط را تکرار کند.
امکان نمونه سازی بدون قید و شرط کلاسها
تعریف کلاس Article1 را به صورت زیر درنظر بگیرید:
public class Article1 { public string Title { get; set; } public string? Subtitle { get; set; } public string Author { get; set; } public DateTime Published { get; set; } }
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net7.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> </Project>
Non-nullable property 'Title' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [CS11Tests]csharp(CS8618) Non-nullable property 'Author' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. [CS11Tests]csharp(CS8618)
مدیریت کردن نحوهی نمونه سازی کلاسها، با وابستگی به سازندههای آن
یکی از روشهای مدیریت مشکلی که تا اینجا بررسی شد، تعریف سازندههای متعددی برای یک کلاس است؛ تا توسط آن بتوان مقدار دهی یک سری از خواص را اجباری کرد:
public class Article2 { public Article2(string title, string subtitle, string author, DateTime published) { Title = title; Subtitle = subtitle; Author = author; Published = published; } public Article2(string title, string author, DateTime published) { Title = title; Author = author; Published = published; } public string Title { get; set; } public string? Subtitle { get; set; } public string Author { get; set; } public DateTime Published { get; set; } }
- تعداد سطرهای تعریف این کلاس، به شدت افزایش یافتهاست.
- با اضافه شدن خواص بیشتری به کلاس، به تعاریف بیشتری نیاز خواهد بود.
- سازندهها کار خاصی را بجز نگاشت مقادیر ارائه شده، به خواص کلاس، انجام نمیدهند.
- نمونه سازی این کلاسها، شکل طولانی و غیرواضح زیر را پیدا میکند و زیبایی inline object initializers را ندارند:
Article2 article = new("C# 11 Required Keyword", "A new language feature", "Name", new DateTime(2022, 11, 12));
البته روش دیگر مدیریت یک چنین اخطارهایی، استفاده از مقدار ویژهی !default است که سبب محو اخطارهای یاد شده میشود؛ اما باز هم مقدار دهی آنرا الزامی نمیکند. فقط به این معنا است که قول میدهیم این خاصیت را در جای دیگری مقدار دهی کنیم و هیچگاه نال نباشد!
public string Title { get; set; } = default!;
مدیریت کردن نحوهی نمونه سازی کلاسها، بدون وابستگی به سازندههای آن در C# 11.0
C# 11 به همراه واژهی کلیدی جدیدی به نام required است تا دیگر نیازی نباشد همانند راه حل فوق، سازندههای متعددی را جهت اجبار به مقدار دهی خواص یک شیء، تعریف کنیم. در این حالت تعریف کلاس Article به صورت زیر خلاصه میشود و دیگر به همراه اخطارهای کامپایلر نمایش داده شده نیز نیست:
public class Article3 { public required string Title { get; set; } public string? Subtitle { get; set; } public required string Author { get; set; } public DateTime Published { get; set; } }
معرفی ویژگی جدید SetsRequiredMembers
کلاس Book زیر را که به همراه یک خاصیت required و دو سازندهاست، درنظر بگیرید:
public class Book { public Book() => Name = string.Empty; public Book(string name) => Name = name; public required string Name { get; set; } }
Book book = new("Book's Name");
Required member 'Book.Name' must be set in the object initializer or attribute constructor. [CS11Tests]csharp(CS9035)
public class Book { [SetsRequiredMembers] public Book() => Name = string.Empty; [SetsRequiredMembers] public Book(string name) => Name = name; public required string Name { get; set; } }
محدودیتهای کار با خواص required
- واژهی کلیدی required را میتوان تنها به خواص و فیلدهای نوعهای class, record, record struct اعمال کرد. امکان اعمال این واژهی کلیدی به اجزای یک اینترفیس وجود ندارد.
- میدان دید اعضای required باید حداقل در حد نوعهای دربرگیرندهی آنها باشند. برای مثال اگر کلاسی public است، نمیتوان در آن یک فیلد required با میدان دید protected را تعریف کرد.
- نوعهای مشتق شدهی از یک نوع پایه، نمیتوانند اعضای required آنرا مخفی کنند و اگر قصد بازنویسی آنرا دارند، باید حتما واژهی کلیدی required را لحاظ کنند.
- اگر سازندهای به سازندهی دیگری از طریق ذکر ()base و یا ()this زنجیر شده باشد نیز باید ویژگی SetsRequiredMembers مرتبط را تکرار کند.
مطالب دورهها
لیست ها و آرایه ها در #F
برای تعریف لیست در #F فقط کافیست از [] و برای جداسازی آیتمهای موجود در لیست از عملگر :: (بخوانید cons) استفاده کنید. #F از لیستهای خالی نیز پشتیبانی میکند. به مثال هایی از این دست توجه کنید
#1 تعریف یک لیست خالی
#2 تعریف یک لیست به همراه یک آیتم
#3 تعریف یک لیست به همراه دو آیتم
قبول دارم که دستورالعمل بالا برای مقدار دهی اولیه به لیست کمی طولانی و سخت است. برای همین میتونید از روش زیر هم استفاده کنید.
*کد بالا یک لیست با دو آیتم که از نوع رشته ای هستند تولید خواهد کرد.
میتونید از عملگر @ برای پیوستن دو لیست به هم نیز استفاده کنید.
نکته : تمام آیتمهای موجود در لیست باید از یک نوع باشند. بعنی امکان تعریف لیستی که دارای آیتم هایی با datatypeهای متفاوت باشد باعث تولید خطای کامپایلری میشود. اما اگر نیاز به لیستی دارید که باید چند datatype رو هم پوشش دهد میتونید از objectها استفاده کنید.
در بالا یک لیست از objectها رو تعریف کرده ایم. فقط دقت کنید برای اینکه آیتمهای موجود در لیست رو تبدیل به object کنیم از دستور box قبل از هر آیتم استفاده کردیم.
در هنگام استفاده از عملگرها @ و :: مقدار لیست تغییر نمیکند بلکه یک لیست جدید تولید خواهد شد.
#1 تعریف لیستی که دارای یک آیتم است.
#2 تعریف لیستی که دارای دو آیتم است(آیتم دوم لیست خود از نوع لیست است)
#3 تعریف لیستی که دارای سه آیتم است(ایتم دوم لیست خود از نوع لیستی است که دارای دو آیتم است)
# از تابع List.rev برای معکوس کردن آیتمهای لیست three استفاده کردیم و مقادیر در لیستی به نام rightWayRound قرار گرفت.
#5 تابع main برای چاپ اطلاعات لیست ها
بعد از اجرا خروجی زیر مشاهده میشود.
تفاوت بین لیستها در #F و لیست و آرایه در دات نت(System.Collection.Generic)
#1 در #F بعد از ساختن یک لیست امکان تغییر در مقادیر عناصر آن وجود ندارد.
#2 در #F بعد از ساختن یک لیست دیگه نمیتونید یک عنصر جدید به لیست اضافه کنید.
#3 جستجوی در لیستهای #F به نسبت لیستها و آرایههای در دات نت کندتر عمل میکند.
استفاده از عبارات در لیست ها
برای تعریف محدوده در لیست میتونیم به راحتی از روش زیر استفاده کنیم
برای ساخت لیستها به صورت داینامیک استفاده از حلقههای تکرار در لیست مجاز است.
کد بالا معادل کد زیر در #C است.
لیستها و الگوی Matching
روش عادی برای کار با لیستها در #F استفاده از الگوی Matching و توابع بازگشتی است.
در مثال بالا ابتدا یک لیست تعریف کردیم که دارای 3 آیتم است و هر آیتم آن خود یک لیست با سه آیتم است.(تمام آیتمها از نوع داده عددی هستند). یک تابع بازگشتی برای پیمایش تمام آیتمهای لیست نوشتم که در اون از الگوی Matching استفاده کردیم.
خروجی :
ماژول لیست
در جدول زیر تعدادی از توابع ماژول لیست رو مشاهده میکنید.
مثال هایی از توابع بالا
مثال هایی از نحوه استفاده seq
#1 seq بامحدوده 1 تا 100 و توالی 10
#2 استفاده از حلقههای تکرار برای تعریف محدوده و توالی در seq
#3 استفاده از <- به جای yield
#4 استفاده از حلقه for به همراه شرط برای فیلتر کردن
چگونگی استفاده از توابع seq
در این بخش به ارائه مثال هایی کاربردیتر از چگونگی استفاده از seq در #F میپردازیم. برای شروع نحوه ساخت یک seq خالی یا empty رو خواهم گفت.
روش ساخت یک seq که فقط یک عنصر را برگشت میدهد.
برای ساختن یک seq همانند لیستها میتونیم از seq.init استفاده کنیم. عدد 5
که بلافاصله بعد از تابع seq.init آمده است نشان دهنده تعداد آیتمها
موجود در seq خواهد بود. seq.iter هم یک تابع مورد نظر رو بر روی تک تک
عناصر seq اجرا خواهد کرد.(همانند list.iter)
خروجی مثال بالا
با استفاده از توابع seq.ofArray , seq.ofList میتونیم seq مورد نظر خود را از لیست یا آرایه مورد نظر بسازیم.
البته این نکته رو هم یادآور بشم که به کمک عملیات تبدیل نوع(type casting) هم میتونیم آرایه رو به seq تبدیل کنیم. به صورت زیر
برای مشخص کردن اینکه آیا یک آیتم در seq موجود است یا نه میتونیم از seq.exists به صورت زیر استفاده کنیم.
اگر seq پاس داده شده به تابع exists خالی باشد یا یک ArgumentNullException متوقف خواهید شد.
برای جستجو و پیدا کردن یک آیتم در seq میتونیم از seq.find استفاده کنیم.
دقت کنید که اگر هیچ آیتمی در sequence با predicate مورد نظر پیدا نشود
یک KeyNotFoundException رخ خواهد داد. در صورتی که مایل نباشید که استثنا
رخ دهد میتوانید از تابع seq.tryFind استفاده کنید. هم چنین خالی بودن
sequence ورودی باعث ArgumentNullExceptionخواهد شد.
استفاده از lambda expression در توابع
lamdaExpressoion از تواناییها مورد علاقه برنامه نویسان دات نت است و کمتر کسی است حاضر به استفاده از آن در کوئریهای linq نباشد. در #F نیز میتوانید از lambda Expression استفاده کنید. در ادامه به بررسی مثال هایی از این دست خواهیم پرداخت.
تابع skipWhile
همانند skipWhile در linq عمل میکند. یعنی یک predicate مورد نظر را بر روی تک تک عناصر یک لیست اجرا میکند و آیتم هایی که شرط برای آنها true باشد نادیده گرفته میشوند و مابقی آیتمها برگشت داده میشوند.
میبینید که predicate
مورد نظر برای تابع skipWhile به صورت lambda expression است که با رنگ
متفاوت نمایش داده شده است.(استفاده از کلمه fun).
خروجی به صورت زیر است:
برای
بازگرداندن یک تعداد مشخص از آیتمهای seq میتونید از توابع seq.take یا
seq.truncate استفاده کنید. ابتدا باید تعداد مورد نظر و بعد لیست مورد نظر
را به عنوان پارامتر مقدار دهی کنید.
مثال:
خروجی
Tuples
tuples در #F به گروهی از مقادیر بی نام ولی مرتب شده که میتوانند انواع متفاوت هم داشته باشند گفته میشود. ساختار کلی آن به صورت ( element , ... , element ) است که هر element خود میتواند یک عبارت نیز باشد.(مشابه کلاس Tuple در #C که به صورت generic استفاده میکنیم)
نکات استفاده از tuple
#1 میتونیم از الگوی Matching برای دسترسی به عناصر tuple استفاده کنیم.
#2 میتونیم از let برای تعربف الگوی tuple استفاده کنیم.
#3 توابع fst و snd مقادیر اول و دوم هر tuple رو بازگشت میدهند
#4 تابعی برای بازگشت عنصر سوم یک tuple وجود ندارد ولی این تابع رو با هم مینویسیم:
کاربرد tuple در کجاست
زمانی که یک تابع باید بیش از یک مقدار را بازگشت دهد از tupleها استفاده میکنیم. برای مثال
خروجی تابع divRem از نوع tuple که دارای 2 مقدار است میباشد.
#1 let emptyList = [] #2 let oneItem = "one " :: [] #3 let twoItem = "one " :: "two " :: []
#2 تعریف یک لیست به همراه یک آیتم
#3 تعریف یک لیست به همراه دو آیتم
قبول دارم که دستورالعمل بالا برای مقدار دهی اولیه به لیست کمی طولانی و سخت است. برای همین میتونید از روش زیر هم استفاده کنید.
let shortHand = ["apples "; "pears"]
میتونید از عملگر @ برای پیوستن دو لیست به هم نیز استفاده کنید.
let twoLists = ["one, "; "two, "] @ ["buckle "; "my "; "shoe "]
نکته : تمام آیتمهای موجود در لیست باید از یک نوع باشند. بعنی امکان تعریف لیستی که دارای آیتم هایی با datatypeهای متفاوت باشد باعث تولید خطای کامپایلری میشود. اما اگر نیاز به لیستی دارید که باید چند datatype رو هم پوشش دهد میتونید از objectها استفاده کنید.
let objList = [box 1; box 2.0; box "three"]
در هنگام استفاده از عملگرها @ و :: مقدار لیست تغییر نمیکند بلکه یک لیست جدید تولید خواهد شد.
#1 let one = ["one "] #2 let two = "two " :: one #3 let three = "three " :: two #4 let rightWayRound = List.rev three #5 let main() = printfn "%A" one printfn "%A" two printfn "%A" three printfn "%A" rightWayRound
#2 تعریف لیستی که دارای دو آیتم است(آیتم دوم لیست خود از نوع لیست است)
#3 تعریف لیستی که دارای سه آیتم است(ایتم دوم لیست خود از نوع لیستی است که دارای دو آیتم است)
# از تابع List.rev برای معکوس کردن آیتمهای لیست three استفاده کردیم و مقادیر در لیستی به نام rightWayRound قرار گرفت.
#5 تابع main برای چاپ اطلاعات لیست ها
بعد از اجرا خروجی زیر مشاهده میشود.
["one "] ["two "; "one "] ["three "; "two "; "one "] ["one "; "two "; "three "]
F#List | Net Array | Net List | |
#1 امکان تغییر در عناصر لیست | No | Yes | Yes |
#2 امکان اضافه کردن عنصر جدید | No | No | Yes |
#3 جستجو | On | O1 | O1 |
#2 در #F بعد از ساختن یک لیست دیگه نمیتونید یک عنصر جدید به لیست اضافه کنید.
#3 جستجوی در لیستهای #F به نسبت لیستها و آرایههای در دات نت کندتر عمل میکند.
استفاده از عبارات در لیست ها
برای تعریف محدوده در لیست میتونیم به راحتی از روش زیر استفاده کنیم
let rangeList = [1..99]
let dynamicList = [for x in 1..99 -> x*x]
for(int x=0;x<99 ; x++) { myList.Add(x*x); }
روش عادی برای کار با لیستها در #F استفاده از الگوی Matching و توابع بازگشتی است.
let listOfList = [[2; 3; 5]; [7; 11; 13]; [17; 19; 23; 29]] let rec concatList l = match l with | head :: tail -> head @ (concatList tail) | [] -> [] let primes = concatList listOfList printfn "%A" primes
خروجی :
[2; 3; 5; 7; 11; 13; 17; 19; 23; 29]
در جدول زیر تعدادی از توابع ماژول لیست رو مشاهده میکنید.
نام تابع | توضیحات |
List.length | تابعی که طول لیست را برمی گرداند |
List.head | تابعی برای برگشت عنصر اول لیست |
List.tail | تمام عناصر لیست را بر میگرداند به جز عنصر اول |
List.init | یک لیست با توجه به تعداد آیتم ایجاد میکند و یم تابع را بر روی تک تک عناصر لیست ایجاد میکند. |
List.append | یک لیست را به عنوان ورودی دریافت میکند و به لیست مورد نظر اضافه میکند و مجموع دو لیست را برگشت میدهد |
List.filter | فقط عناصری را برگشت میدهد که شرط مورد نظر بر روی آنها مقدار true را برگشت دهد |
List.map | یک تابع مورد نظر را بر روی تک تک عناصر لیست اجرا میکند و لیست جدید را برگشت میدهد |
List.iter | یک تابع مورد نظر را بر روی تک تک عناصر لیست اجرا میکند |
List.zip | مقادیر دو لیست را با هم تجمیع میکند و لیست جدید را برگشت میدهد. اگر طول 2 لیست ورودی یکی نباشد خطا رخ خواهدداد |
List.unzip | درست برعکس تابع بالا عمل میکند |
List.toArray | لیست را تبدیل به آرایه میکند |
List.ofArray | آرایه را تبدیل به لیست میکند |
List.head [5; 4; 3] List.tail [5; 4; 3] List.map (fun x -> x*x) [1; 2; 3] List.filter (fun x -> x % 3 = 0) [2; 3; 5; 7; 9]
Sequence Collection
seq در #F یک توالی از عناصری است که هم نوع باشند. عموما از sequenceها زمانی استفاده میکنیم که یک مجموعه از دادهها با تعداد زیاد و مرتب شده داشته باشیم ولی نیاز به استفاده از تمام عناصر آن نیست. کارایی sequence در مجموعههای با تعداد زیاد از listها به مراتب بهتر است. sequenceها را با تابع seq میشناسند که معادل IEnumerable در دات نت است. بنابر این هر مجمو عه ای که IEnumerable رو در دات نت پیاده سازی کرده باشد در #F با seq قابل استفاده است.مثال هایی از نحوه استفاده seq
#1 seq بامحدوده 1 تا 100 و توالی 10
seq { 0 .. 10 .. 100 }
seq { for i in 1 .. 10 do yield i * i }
seq { for i in 1 .. 10 -> i * i }
let isprime n = let rec check i = i > n/2 || (n % i <> 0 && check (i + 1)) check 2 let aSequence = seq { for n in 1..100 do if isprime n then yield n }
در این بخش به ارائه مثال هایی کاربردیتر از چگونگی استفاده از seq در #F میپردازیم. برای شروع نحوه ساخت یک seq خالی یا empty رو خواهم گفت.
let seqEmpty = Seq.empty
let seqOne = Seq.singleton 10
let seqFirst5MultiplesOf10 = Seq.init 5 (fun n -> n * 10) Seq.iter (fun elem -> printf "%d " elem) seqFirst5MultiplesOf10
0 10 20 30 40
let seqFromArray2 = [| 1 .. 10 |] |> Seq.ofArray
let seqFromArray1 = [| 1 .. 10 |] :> seq<int>
let containsNumber number seq1 = Seq.exists (fun elem -> elem = number) seq1 let seq0to3 = seq {0 .. 3} printfn "For sequence %A, contains zero is %b" seq0to3 (containsNumber 0 seq0to3)
برای جستجو و پیدا کردن یک آیتم در seq میتونیم از seq.find استفاده کنیم.
let isDivisibleBy number elem = elem % number = 0 let result = Seq.find (isDivisibleBy 5) [ 1 .. 100 ] printfn "%d " result
استفاده از lambda expression در توابع
lamdaExpressoion از تواناییها مورد علاقه برنامه نویسان دات نت است و کمتر کسی است حاضر به استفاده از آن در کوئریهای linq نباشد. در #F نیز میتوانید از lambda Expression استفاده کنید. در ادامه به بررسی مثال هایی از این دست خواهیم پرداخت.
تابع skipWhile
همانند skipWhile در linq عمل میکند. یعنی یک predicate مورد نظر را بر روی تک تک عناصر یک لیست اجرا میکند و آیتم هایی که شرط برای آنها true باشد نادیده گرفته میشوند و مابقی آیتمها برگشت داده میشوند.
let mySeq = seq { for i in 1 .. 10 -> i*i }
let printSeq seq1 = Seq.iter (printf "%A ") seq1; printfn ""
let mySeqSkipWhileLessThan10 = Seq.skipWhile (fun elem -> elem < 10) mySeq
mySeqSkipWhileLessThan10 |> printSeq
خروجی به صورت زیر است:
16 25 36 49 64 81 100
مثال:
let mySeq = seq { for i in 1 .. 10 -> i*i } let truncatedSeq = Seq.truncate 5 mySeq let takenSeq = Seq.take 5 mySeq let printSeq seq1 = Seq.iter (printf "%A ") seq1; printfn ""
#1 truncatedSeq |> printSeq #3 takenSeq |> printSeq
1 4 9 16 25 //truncate 1 4 9 16 25 //take
Tuples
tuples در #F به گروهی از مقادیر بی نام ولی مرتب شده که میتوانند انواع متفاوت هم داشته باشند گفته میشود. ساختار کلی آن به صورت ( element , ... , element ) است که هر element خود میتواند یک عبارت نیز باشد.(مشابه کلاس Tuple در #C که به صورت generic استفاده میکنیم)
// Tuple of two integers. ( 1, 2 ) // Triple of strings. ( "one", "two", "three" ) // Tuple of unknown types. ( a, b ) // Tuple that has mixed types. ( "one", 1, 2.0 ) // Tuple of integer expressions. ( a + 1, b + 1)
#1 میتونیم از الگوی Matching برای دسترسی به عناصر tuple استفاده کنیم.
let print tuple1 = match tuple1 with | (a, b) -> printfn "Pair %A %A" a b
let (a, b) = (1, 2)
let c = fst (1, 2) // return 1 let d = snd (1, 2)// return 2
let third (_, _, c) = c
زمانی که یک تابع باید بیش از یک مقدار را بازگشت دهد از tupleها استفاده میکنیم. برای مثال
let divRem a b = let x = a / b let y = a % b (x, y)
DateTime در طبقه بندی سی شارپ، جزء Strcut Typeها قرار میگیرد . عمدتا از DateTime برای مدیریت تاریخ، زمان و یا تاریخ-زمان استفاده میشود. خیلی از اوقات ما نیاز داریم تا رشتهای را به نوع تاریخ تبدیل کنیم تا بتوانیم عملیات مختلفی، همچون محاسبهی اختلاف دو تاریخ، روز هفته، روز ماه و غیره را بدست آوریم. در دات نت متدهای مختلفی وجود دارند که جداسازی تاریخ را از یک رشته برای ما فراهم میکنند:
تابع () DateTime.Parse :
تابع ()DateTime.ParsExact
تابع ()DateTime.TryParse
تابع ()DateTime.TryParseExact
آنالیز متدهای معرفی شده
- Convert.ToDateTime()
- DateTime.Parse()
- DateTime.ParseExact()
- DateTime.TryParse()
- DateTime.TryParseExact()
در این مطلب این متدها و تفاوت آنها را بررسی میکنیم.
تابع ()Convert.ToDateTime
این تابع یک رشتهی با فرمت مشخص را به تاریخ و زمان تبدیل میکند. overloadها مختلف این تابع را در بخش زیر مشاهده میکنید:
• ToDateTime(string value)
Value : رشتهای از تاریخ و زمان است.
• ToDateTime(string value,IFormatProvider provide)
Value : رشتهای از تاریخ و زمان است.
Provider : اطلاعات فرهنگ مورد نظر را فراهم میکند.
CultureInfo culture = new CultureInfo("en-US"); DateTime tempDate = Convert.ToDateTime("1/1/2010 12:10:15 PM", culture);
در اینجا en-us اطلاعاتی را دربارهی فرهنگ کشور آمریکا، ارائه میدهد. لیست کامل فرهنگهای موجود در net. را میتوانید در اینجا مشاهده کنید.
اگر رشتهی ما تهی (null) نباشد، بصورت درونی متد ()DateTime.Parse فراخوانی و نتیجهی آن بازگردانده میشود. اما در صورتیکه رشتهی ارسالی ما تهی باشد، مقدار بازگردانده شده مقدار DateTime.MinValue که برابر با 0001/1/1 میباشد، بازگردانده میشود.
نمونهای از خروجی این تابع با ورودیهای مختلف :
string datestr = null; Console.WriteLine(Convert.ToDateTime(datestr));//0001-01-01T00:00:00 datestr = "wrong string"; Console.WriteLine(Convert.ToDateTime(datestr)); //Unhandled Exception: System.FormatException: //The string was not recognized as a valid DateTime. //There is an unknown word starting at index 0. datestr = "Tue Dec 30,2015"; Console.WriteLine(Convert.ToDateTime(datestr)); //Unhandled Exception: System.FormatException: //String was not recognized as a valid DateTime.
تابع () DateTime.Parse :
این تابع یک رشتهی با فرمت مشخص را به تاریخ و زمان تبدیل میکند. دو overload این تابع را در زیر میبینیم:
• DateTime.Parse(string value)
Value : رشتهای از تاریخ و زمان میباشد.
• DateTime.Parse(String value, IFormatProvider provider)
Value : رشتهای از تاریخ و زمان میباشد.
Provider : اطلاعات فرهنگ مورد نظر را فراهم میکند.
- DateTime.Parse(String value, IFormatProvider provider, DateTypeStyles styles)
Value : رشتهای از تاریخ و زمان میباشد.
Provider : اطلاعات فرهنگ مورد نظر را فراهم میکند
Styles : از طریق این پارامتر، تنظیمات قالب بندی رشتهی دریافتی برای سفارشی سازی کردن عملیات پردازش تعریف میشود. فرض کنید میخواهید کلیهی فضاهای خالی (Space) را که قبل و بعد از رشتهی تاریخ هستند و نه در داخل رشتهی تاریخ، در زمان جداسازی و پردازش در نظر نگیرید. این پارامتر میتواند در اینجا به کمک ما بیاید (DateTimeStyles.AllowWhiteSpaces). مشاهدهی لیست کامل این خصوصیت از اینجا.
اگر مقدار رشته تهی باشد، استثنای Null نمایش داده خواهد شد (ArgumentNullException ) و اگر فرمت تاریخ ورودی صحیح نباشد، با استثنای فرمت غیرمعتبر روبرو خواهیم شد (FormatException).
string datestr = null; Console.WriteLine(DateTime.Parse(datestr)); //// Exception: Argument null exception datestr = "wrong string"; Console.WriteLine(DateTime.Parse(datestr)); //// Exception: The string was not recognized as a valid DateTime. //// There is an unknown word starting at index 0. datestr = "Tue Dec 30, 2015"; //Unhandled Exception: System.FormatException: //String was not recognized as a valid DateTime. Console.WriteLine(DateTime.Parse(datestr));
تابع ()DateTime.ParsExact
این تابع رشتهای شامل تاریخ و زمان را بههمراه فرهنگ ارسالی، دریافت و آن را تبدیل به نوع DateTime میکند. فرمت رشتهی ارسالی باید با فرمت استاندارد رشتهی تاریخ یکسان باشد. overloadهای مختلف این تابع را در زیر مشاهده میکنید:
• DateTime.ParseExact(string value, string format, IFormatProvider provider)
Value : رشتهای از تاریخ و زمان میباشد.
Provider : اطلاعات فرهنگ مورد نظر را فراهم میکند.
• DateTime.ParseExact(string value, string format, IFormatProvider provider, DateTimeStyles style)
Value : رشتهای از تاریخ و زمان میباشد.
Format : فرمت مورد نظر برای نمایش تاریخ بعد از تبدیل را مشخص میکند.
Provider : اطلاعات فرهنگ مورد نظر را فراهم میکند.
Styles : از طریق این پارامتر تنظیمات قالب بندی رشته برای سفارشی کردن عملیات جداسازی و پردازش تعریف میشود.
• DateTime.ParseExact(string value, string[] formats, IFormatProvider provider, DateTimeStyles style)
Value : رشتهای از تاریخ و زمان میباشد.
Format : فرمت مورد نظر برای نمایش تاریخ بعد از تبدیل را مشخص میکند. تفاوت این حالت با حالت قبل این است که لیستی از فرمتها را قبول میکند و حداقل باید یک فرمت با رشتهی ارسالی قابل انطباق باشد.
Provider : اطلاعات فرهنگ مورد نظر را فراهم میکند.
Styles : از طریق این پارامتر تنظیمات قالب بندی رشته برای سفارشی کردن عملیات جداسازی تعریف میشود.
اگر مقدار رشته تهی باشد، استثنای Null نمایش داده خواهد شد (ArgumentNullException) و اگر فرمت تاریخ ورودی صحیح نباشد، با استثنای فرمت غیرمعتبر روبرو خواهیم شد(FormatException).
فرمت رشتهی تاریخ حتما باید با فرمت نوع تاریخ منطبق باشد. به همین منظور حالتهای مختلفی را در آرایه میتوان پیش بینی کرد. بطور مثال ممکن است رشتهی ما بصورت "2012-2-1" و یا "2012/2/1" باشد. بنابر این فرمتهای "MM/dd/yyyy" و "MM-dd-yyyy" را از طریق آرایه ارسال میکنیم.
برای درک بهتر این موضوع، کدهای زیر را مشاهده کنید:
string datestr = null; CultureInfo provider = CultureInfo.InvariantCulture; Console.WriteLine(DateTime.ParseExact(datestr, "mm/dd/yyyy", provider)); //Unhandled Exception: System.ArgumentNullException: //String reference not set to an instance of a String. datestr = "wrong date"; Console.WriteLine(DateTime.ParseExact(datestr, "mm/dd/yyyy", provider)); //Unhandled Exception: System.FormatException: //String was not recognized as a valid DateTime datestr = "Tue Dec 30, 2015"; Console.WriteLine(DateTime.ParseExact(datestr, "mm/dd/yyyy", provider)); //Unhandled Exception: System.FormatException: //String was not recognized as a valid DateTime. datestr = "10-22-2015"; Console.WriteLine(DateTime.ParseExact(datestr, "MM-dd-yyyy", provider)); //30/07/1394 12:00:00 ق.ظ datestr = "10-22-2015"; Console.WriteLine(DateTime.ParseExact(datestr, new string[] {"MM-dd-yyyy", "MM/dd/yyyy", "MM.dd.yyyy"}, provider, DateTimeStyles.None)); //30/07/1394 12:00:00 ق.ظ
تابع ()DateTime.TryParse
این تابع رشتهای شامل تاریخ و زمان را بههمراه فرهنگ مشخصی، دریافت و آن را تبدیل به نوع DateTime میکند و یک مقدار bool را برای اعلان این موضوع که عملیات تبدیل با موفقیت انجام شده است یا خیر، باز میگرداند. فرمت رشتهی ارسالی باید با فرمت رشتهی تاریخ یکسان باشد. overloadهای مختلف این تابع را در زیر مشاهده میکنید:
• DateTime.TryParse (String value, out DateTime result)
Value : رشتهای از تاریخ و زمان میباشد.
Result : مقدار تاریخ را بعد از جداسازی در خود ذخیره میکند.
• DateTime.TryParse(String value, IFormatProvider provider, DateTimeStyles styles, out DateTime result)
Value : رشتهای از تاریخ و زمان میباشد.
Provider : اطلاعات فرهنگ مورد نظر را فراهم میکند.
Styles : از طریق این پارامتر میتوانیم قالب پارامتر ارسالی را مشخص کنیم (مثلا نادیده گرفتن فضاهای خالی).
Result : مقدار تاریخ را بعد از جداسازی در خود ذخیره میکند.
این تابع همیشه سعی میکند رشتهی تاریخ را جداسازی کند. در صورت موفقیت در عملیات جداسازی رشته، تاریخ معتبر را بر میگرداند و در غیر اینصورت میزان کوچکترین تاریخ یا همان MinValue را که قبلا در همین مطلب اشاره شد، باز میگرداند. در صورتی هم که رشته، null یا با فرمت رشتهای غیر معتبر باشد، همان مقدار DateTime.MinValue بازگردانده میشود. همیشه با کنترل مقدار بازگشتی صحت انجام عملیات را میتوان متوجه شد (true موفقیت در عملیات جداسازی و false عدم موفقیت در عملیات جداسازی).
نکتهی مهم عدم پرتاب استثتاء در صورت عدم موفقیت در عملیات جداسازی میباشد.
string datestr = null; DateTime temp; Console.WriteLine(DateTime.TryParse(datestr, out temp)); Console.WriteLine(temp); //False //0001 - 01 - 01T00: 00:00 datestr = "wrong date"; Console.WriteLine(DateTime.TryParse(datestr, out temp)); Console.WriteLine(temp); //False //0001 - 01 - 01T00: 00:00 datestr = "Tue Dec 30, 2015"; Console.WriteLine(DateTime.TryParse(datestr, out temp)); Console.WriteLine(temp); //False //0001 - 01 - 01T00: 00:00
تابع ()DateTime.TryParseExact
این تابع رشتهای شامل تاریخ و زمان را بههمراه فرهنگ مشخصی دریافت و آن را تبدیل به نوع DateTime میکند. رشتهی ارسالی باید منطبق با فرمت تاریخ باشد. overloadهای مختلف این تابع را در زیر مشاهده میکنید:
• DateTime.ParseExact(string value, string format, IFormatProvider provider, DateTimeStyles style)
Value : رشتهای از تاریخ و زمان میباشد.
Format : فرمت مورد نظر را برای نمایش تاریخ بعد از تبدیل، مشخص میکند.
Provider : اطلاعات فرهنگ مورد نظر را فراهم میکند.
Styles : از طریق این پارامتر میتوانیم قالب پارامتر ارسالی را مشخص کنیم (مثلا نادیده گرفتن فضاهای خالی).
• DateTime.ParseExact(string value, string[] formats, IFormatProvider provider, DateTimeStyles style)
Value : رشتهای از تاریخ و زمان میباشد.
Format : فرمت مورد نظر برای نمایش تاریخ بعد از تبدیل را مشخص میکند و میتوان آرایهای از فرمتها را در اینجا ارسال کرد.
Provider : اطلاعات فرهنگ مورد نظر را فراهم میکند.
Styles : از طریق این پارامتر میتوانیم قالب پارامتر ارسالی را مشخص کنیم (مثلا نادیده گرفتن فضاهای خالی).
این تابع را در شرایط زیر، مقدار (MinValue( 1/1/0001 12:00:00 AM را باز میگرداند:
• رشته null باشد.
• رشته خالی باشد "".
• فرمت رشتهی تاریخ غلط باشد.
• رشته با فرمت معرفی شدهی در provider، انطباق نداشته باشد.
• تنها در صورتی که مقدار انتخابی DateTimeStyle معتبر نباشد، استثنایی رخ میدهد.
همچنین همیشه پس از انجام عملیات، مقداری بولین را برای نمایش موفقیت یا عدم موفقیت جدا سازی، باز میگرداند.
string datestr = null; DateTime temp; CultureInfo provider = CultureInfo.InvariantCulture; Console.WriteLine(DateTime.TryParseExact(datestr, "MM/dd/yyyy", provider, DateTimeStyles.None, out temp)); Console.WriteLine(temp); //False //1/1/0001 12:00:00 AM datestr = "wrong date"; Console.WriteLine(DateTime.TryParseExact(datestr, "MM/dd/yyyy", provider, DateTimeStyles.None, out temp)); Console.WriteLine(temp); //False //1/1/0001 12:00:00 AM datestr = "Tue Dec 30, 2015"; Console.WriteLine(DateTime.TryParseExact(datestr, "MM/dd/yyyy", provider, DateTimeStyles.None, out temp)); Console.WriteLine(temp); //False //1/1/0001 12:00:00 AM datestr = "10‐22‐2015"; Console.WriteLine(DateTime.TryParseExact(datestr, "MM/dd/yyyy", provider, DateTimeStyles.None, out temp)); Console.WriteLine(temp); //False //1/1/0001 12:00:00 AM datestr = "10‐22‐2015"; Console.WriteLine(DateTime.TryParseExact( datestr, "MM‐dd‐yyyy", provider, DateTimeStyles.None, out temp)); Console.WriteLine(temp); //True //30/07/1394 12:00:00 ق.ظ datestr = "10‐12‐2015"; Console.WriteLine(DateTime.TryParseExact(datestr, new string[] { "MM/dd/yyyy", "MM‐dd‐yyyy", "MM.dd.yyyy" }, provider, DateTimeStyles.None, out temp)); Console.WriteLine(temp); //True //20/07/1394 12:00:00 ق.ظ
آنالیز متدهای معرفی شده
نوع DateTime متدهای مختلفی را برای جداسازی رشته و تبدیل آن به تاریخ دارد. تفاوتهای این متدها را در بخش زیر بررسی میکنیم :
تفاوت Parse و ConvertToDateTime:
این دو متد شبیه به هم هستند، اما چند تفاوت کوچک با هم دارند:
• اگر مقدار رشتهی ارسالی null باشد، متد Parse، یک استثناء را ارسال میکند و متد ConvertToDateTime مقدار MinValue را باز میگرداند.
• در متد Parse میتوان یک پارامتر اضافهتر نیز ارسال کرد که DateTimeStyle نامیده میشود. اما متد ConvertToDateTime این قابلیت را ندارد.
• تابع ConvertToDateTime بهصورت داخلی از متد DateTime.Parse بههمراه فرهنگ جاری استفاده میکند.
تفاوت تابع Parseو ParseExact:
این دو تابع شبیه به هم هستند، اما میتوان یک پارامتر اضافی format را نیز به تابع ParseExact ارسال کرد. این پارامتر به ما کمک میکند تا رشتهای را که فرمت متفاوتی از حالت معمولی دارد، به تاریخ تبدیل کنیم. مثلا اگر رشتهی "11232015" بدین شکل باشد، فرمت باید به شکل "MMddyyyy" تعریف شود.
تفاوت تابع Parse و TryParse:
این دو متد شبیه به هم هستند، با این تفاوت که تابع TryParse در صورت عدم موفقیت جداسازی رشته، استثنائی را ارسال نمیکند و همیشه مقدار MinValue را در صورت عدم موفقیت در تبدیل، باز میگرداند.
تفاوت تابع TryParse و TryParseExact:
هر دو تابع شبیه به هم هستند؛ بجز در پارامتر format. تابع TryParseExact از یک پارامتر اضافهی format استفاده میکند. ولی تابع TryParse اگر نتواند فرمت مورد نیاز را فراهم کند، مقدار minValue را باز میگرداند.
زیرنویسهای فارسی قسمت آخر «Building Windows 8 Metro Apps in C# and XAML» را از اینجا میتونید دریافت کنید.
این قسمت برای کسانی که میخواهند مروری بر مفاهیم Binding موجود در WPF و سیلورلایت داشته باشند و همچنین تفاوتهای آنرا با نمونه موجود در WinRT بررسی کنند، بسیار مفید است. در کل سیستم Binding موجود در WinRT یک نمونه ساده شده آنچیزی است که در سیلورلایت موجود است (و البته سیلورلایت هم یک نمونه ساده شده WPF است!).
برای مثال خاصیت UpdateSourceTrigger موجود در عبارات Binding مرتبط با WPF و سیلورلایت فعلا در WinRT وجود ندارد.
تفاوت دیگر این است که هرچند اینترفیس INotifyPropertyChanged در WinRT هم وجود دارد اما نمونه مهیای در فضای نام جدیدی به نام windows.ui.xaml.data توسط WinRT شناسایی میشود و اگر کدهای سایر فناوریهای مشابه را به سیستم مترو تبدیل کنید، کار نخواهند کرد! چون این اینترفیس پیشتر در فضای نام System.ComponentModel تعریف شده بود و هنوز هم حضور دارد (فقط در حد یک تغییر سطر تعاریف فضاهای نام کفایت میکند).
یک تله دیگر هم در WinRT وجود دارد. در اینجا هم کلاسی به نام DependencyObject وجود دارد که ... معادل نمونه مشابه WPF و Silverlight نیست و XAML امکان تشخیص خودکار تغییرات خواص آنرا ندارد.
همچنین اینترفیس INotifyCollectionChanged مرتبط با ObservableCollection موجود در WPF و Silverlight در WinRT فعلا وجود خارجی ندارند (هرچند هنوز در خود دات نت فریم ورک وجود دارند، اما کار نمیکنند). به نظر قرار است تا قبل از ارائه نهایی ویندوز 8 در این مورد تصمیم گیری شود. اما در اینجا باید از IObservableVector استفاده کرد! (کلا این کلمه Vector ابراز وجود زاید طراحان سی++ مترو است! یعنی ما هنوز هم زندهایم و سی++ هنوز هم مهم است!)
نحوه گروه بندی اطلاعات نیز تغییر کرده است و باید منبع دادهای، اینترفیس جدید IGroupInfo را پیاده سازی کند. به علاوه CollectionViewSource آن نیز فعلا قابلیتهای جستجو و مرتب سازی موجود در WPF و سیلورلایت را ارائه نمیدهد.
سلام.
علت Return False که آخر این دستور گزاشتید چیست؟
OnClientClick="validate();return false;
ممنون.
علت Return False که آخر این دستور گزاشتید چیست؟
OnClientClick="validate();return false;
ممنون.
اشتراکها
آشنایی با سازندههای Static
Timeouts، Deadlocks و قطعیهای احتمالی و موقت اتصال به بانک اطلاعاتی در شبکه، جزئی از ساختار دنیای واقعی هستند. در EF 6 برای پیاده سازی سعی مجدد در اتصال و انجام مجدد عملیات، ویژگی خاصی تحت عنوان connection resiliency اضافه شدهاست که در ادامه مثالی از آنرا بررسی خواهیم کرد.
پیاده سازیهای پیش فرض موجود
برای پیاده سازی منطق سعی مجدد در اتصال، باید اینترفیس IDbExecutionStrategy پیاده سازی شود. در EF 6 حداقل 4 نوع پیاده سازی پیش فرض از آن به صورت توکار ارائه شدهاست:
الف) DefaultExecutionStrategy : حالت پیش فرض است و در صورت بروز مشکل، سعی مجددی را در اتصال، به عمل نخواهد آورد.
ب) DefaultSqlExecutionStrategy : برای کارهای درونی EF از آن استفاده میشود. سعی مجددی در اتصال قطع شده نخواهد کرد؛ اما جزئیات خطاهای بهتری را در اختیار مصرف کننده قرار میدهد.
ج) DbExecutionStrategy : هدف از آن تهیه یک کلاس پایه است برای نوشتن استراتژیهای سعی مجدد سفارشی.
د) SqlAzureExecutionStrategy : یک نمونه DbExecutionStrategy سفارشی تهیه شده برای ویندوز اژور است. برای فعال سازی و تعریف آن نیز باید به نحو ذیل عمل کرد:
تهیه یک DbExecutionStrategy سفارشی برای SQL Server
همانطور که عنوان شد، هدف از کلاس DbExecutionStrategy، تهیه یک کلاس پایه، جهت نوشتن منطق سعی مجدد در اتصال به بانک اطلاعاتی است و این مورد از دیتابیسی به دیتابیس دیگر میتواند متفاوت باشد؛ زیرا خطاهایی را که ارائه میدهند، یکسان و یک دست نیستند. در ادامه یک پیاده سازی سفارشی را از DbExecutionStrategy، جهت SQL Server مرور خواهیم کرد:
در اینجا کار با بازنویسی متد ShouldRetryOn شروع میشود. این متد اگر پس از بررسی استثنای دریافتی، مقدار true را برگرداند، به معنای نیاز به سعی مجدد در اتصال است و برعکس. سازنده پیش فرض این کلاس طوری تنظیم شدهاست که 5 بار سعی مجدد کند؛ با فواصل زمانی 7 ثانیه. اگر میخواهید این زمان را صریحا تعیین کنید باید متد GetNextDelay کلاس پایه را نیز بازنویسی کرد:
در ادامه برای استفاده از آن خواهیم داشت:
این کلاس به صورت خودکار توسط EF از اسمبلی جاری استخراج شده و استفاده خواهد شد. بنابراین نیازی نیست جایی معرفی شود. فقط باید در کدها حضور داشته باشد. همچنین ذکر System.Data.SqlClient نیز ضروری است؛ از این جهت که خطاهای بازگشت داده شده مانند 1205 و امثال آن، در بانکهای اطلاعاتی مختلف، میتوانند کاملا متفاوت باشند.
پیاده سازیهای پیش فرض موجود
برای پیاده سازی منطق سعی مجدد در اتصال، باید اینترفیس IDbExecutionStrategy پیاده سازی شود. در EF 6 حداقل 4 نوع پیاده سازی پیش فرض از آن به صورت توکار ارائه شدهاست:
الف) DefaultExecutionStrategy : حالت پیش فرض است و در صورت بروز مشکل، سعی مجددی را در اتصال، به عمل نخواهد آورد.
ب) DefaultSqlExecutionStrategy : برای کارهای درونی EF از آن استفاده میشود. سعی مجددی در اتصال قطع شده نخواهد کرد؛ اما جزئیات خطاهای بهتری را در اختیار مصرف کننده قرار میدهد.
ج) DbExecutionStrategy : هدف از آن تهیه یک کلاس پایه است برای نوشتن استراتژیهای سعی مجدد سفارشی.
د) SqlAzureExecutionStrategy : یک نمونه DbExecutionStrategy سفارشی تهیه شده برای ویندوز اژور است. برای فعال سازی و تعریف آن نیز باید به نحو ذیل عمل کرد:
public class MyConfiguration : DbConfiguration { public MyConfiguration() { SetExecutionStrategy("System.Data.SqlClient", () => new SqlAzureExecutionStrategy()); } }
تهیه یک DbExecutionStrategy سفارشی برای SQL Server
همانطور که عنوان شد، هدف از کلاس DbExecutionStrategy، تهیه یک کلاس پایه، جهت نوشتن منطق سعی مجدد در اتصال به بانک اطلاعاتی است و این مورد از دیتابیسی به دیتابیس دیگر میتواند متفاوت باشد؛ زیرا خطاهایی را که ارائه میدهند، یکسان و یک دست نیستند. در ادامه یک پیاده سازی سفارشی را از DbExecutionStrategy، جهت SQL Server مرور خواهیم کرد:
public class SqlServerExecutionStrategy : DbExecutionStrategy { public SqlServerExecutionStrategy() { } public SqlServerExecutionStrategy(int maxRetryCount, TimeSpan maxDelay) : base(maxRetryCount, maxDelay) { } protected override bool ShouldRetryOn(Exception ex) { var sqlException = ex as SqlException; if (sqlException == null) return false; // don't retry foreach (var error in sqlException.Errors.Cast<SqlError>()) { switch (error.Number) { case 1205: // Deadlock case -1: // Timeout case -2: // Timeout return true; // retry } } return false; } }
protected override TimeSpan? GetNextDelay(Exception lastException) { return base.GetNextDelay(lastException); }
public class MyDbConfiguration : DbConfiguration { public MyDbConfiguration() { SetExecutionStrategy("System.Data.SqlClient", () => new SqlServerExecutionStrategy()); } }
نظرات مطالب
مدیریت سفارشی سطوح دسترسی کاربران در MVC
سلام؛ من هم مشکل ایشون دارم و رولها کش نمیشه و هر بار متد GetRolesForUser اجرا میشود. اون هم نه یکبار بلکه به تعداد زیاد و بار زیادی به دیتابیس وارد میکنه. لینک شما هم پیغام زیر و میدهد:
An update is available for the .NET Framework 4.5 in Windows 7 SP1, Windows Server 2008 R2 SP1, Windows Server 2008 SP2, and Windows Vista SP2: January 2013
اما ویندوز من 8 هست و پیغام سایت برای ویندوزهای 2008و7وvista هستش. با گشتن هم دیدم بعضیها خودشون متد را دستی کش کردن
public override string[] GetRolesForUser(string username) { var cacheKey = string.Format("{0}:{1}", username, ApplicationName); var cache = HttpContext.Current.Cache; var roles = cache[cacheKey] as string[]; if (null == roles) { using (var db = new Uas3Context()) { var u = new EfStudentService(db); roles=u.GetUserRoles(username); cache.Insert(cacheKey, roles, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration); } } return roles; }
اما این متد و من کش کردم باقی متدها چی؟ کل متدها را همین طوری کش کنم؟ این کد هم به نظرم ناقصه . چون با تغییر دیتابیس به روز نمیشه و صرفا درصورت وجود کش اطلاعات میخونه. اصلا چرا در دات نت 4.5 این مشکل هست و چرا بر روی ویندوز 8 این پیغام داده میشود؟