The main change in this release is a security fix, and it’s possible you
will need to change your own code to adapt. Here’s why: jQuery used a
regex in its jQuery.htmlPrefilter
method to ensure that all closing tags were XHTML-compliant when passed
to methods. For example, this prefilter ensured that a call like jQuery("<div class='hot' />")
is actually converted to jQuery("<div class='hot'></div>")
. Recently, an issue was reported that demonstrated the regex could introduce a cross-site scripting (XSS) vulnerability.
Bootstrap 4.5.0 منتشر شد
- New interaction utilities. Quickly set
user-select
with the new utilities and Sass map. - New Reboot style for pointer cursors. We now include a
role="button"
selector in Reboot to setcursor: pointer
on non-<button>
element buttons. - Examples are now downloadable. We’ve added a script to zip up and offer all our Examples as their own download from the docs.
- Saved ~5% from the compressed minified JS builds.
الگوهای طراحی، سندها و راه حلهای از پیش تعریف شده و تست شدهای برای مسائل و مشکلات روزمرهی برنامه نویسی میباشند که هر روزه ما را درگیر خودشان میکنند. هر چقدر مقیاس پروژه وسیعتر و تعداد کلاسها و اشیاء بزرگتر باشند، درگیری برنامه نویس و چالش برای مرتب سازی و خوانایی برنامه و همچنین بالا بردن کارآیی و امنیت افزونتر میشود. از همین رو استفاده از ساختارهایی تست شده برای سناریوهای یکسان، امری واجب تلقی میشود.
الگوهای طراحی از لحاظ سناریو، به سه گروه عمده تقسیم میشوند:
1- تکوینی: هر چقدر تعداد کلاسها در یک پروژه زیاد شود، به مراتب تعداد اشیاء ساخته شده از آن نیز افزوده شده و پیچیدگی و درگیری نیز افزایش مییابد. راه حلهایی از این دست، تمرکز بر روی مرکزیت دادن به کلاسها با استفاده از رابطها و کپسوله نمودن (پنهان سازی) اشیاء دارد.
2- ساختاری: گاهی در پروژهها پیش میآید که میخواهیم ارتباط بین دو کلاس را تغییر دهیم. از این رو امکان از هم پاشی اجزایِ دیگر پروژه پیش میآید. راه حلهای ساختاری، سعی در حفظ انسجام پروژه در برابر این دست از تغییرات را دارند.
3- رفتاری: گاهی بنا به مصلحت و نیاز مشتری، رفتار یک کلاس میبایستی تغییر نماید. مثلا چنانچه کلاسی برای ارائه صورتحساب داریم و در آن میزان مالیات 30% لحاظ شده است، حال این درصد باید به عددی دیگر تغییر کند و یا پایگاه داده به جای مشاهدهی تعدادِ معدودی گره از درخت، حال میبایست تمام گرهها را ارائه نماید.
الگوی فکتوری:
الگوی فکتوری در دستهء اول قرار میگیرد. من در اینجا به نمونهای از مشکلاتی که این الگو حل مینماید، اشاره میکنم:
فرض کنید یک شرکت بزرگ قصد دارد تا جزییات کامل خرید هر مشتری را با زدن دکمه چاپ ارسال نماید. چنین شرکت بزرگی بر اساس سیاستهای داخلی، بر حسب میزان خرید، مشتریان را به چند گروه مشتری معمولی و مشتری ممتاز تقسیم مینماید. در نتیجه نمایش جزییات برای آنها با احتساب میزان تخفیف و به عنوان مثال تعداد فیلدهایی که برای آنها در نظر گرفته شده است، تفاوت دارد. بنابراین برای هر نوع مشتری یک کلاس وجود دارد.
یک راه این است که با کلیک روی دکمهی چاپ، نوع مشتری تشخیص داده شود و
به ازای نوع مشتری، یک شیء از کلاس مشخص شده برای همان نوع ساخته شود.
// Get Customer Type from Customer click on Print Button int customerType = 0; // Create Object without instantiation object obj; //Instantiate obj according to customer Type if (customerType == 1) { obj = new Customer1(); } else if (customerType == 2) { obj = new Customer2(); } // Problem: // 1: Scattered New Keywords // 2: Client side is aware of Customer Type
همانگونه که مشاهده مینمایید در این سبک کدنویسی غیرحرفهای، مشکلاتی مشهود است که قابل اغماض نیستند. در ابتدا سمت کلاینت دسترسی مستقیم به کلاسها دارد و همانگونه که در شکل بالا قابل مشاهده است کلاینت مستقیما به کلاس وصل است. مشکل دوم عدم پنهان سازی کلاس از دید مشتری است.
راه حل: این مشکل با استفاده از الگوی فکتوری قابل حل است. با استناد به الگوی فکتوری، کلاینت تنها به کلاس فکتوری و یک اینترفیس دسترسی دارد و کلاسهای فکتوری و اینترفیس، حق دسترسی به کلاسهای اصلی برنامه را دارند.
گام نخست: در ابتدا یک class library به نام Interface ساخته و در آن یک کلاس با نام ICustomer می سازیم که متد Report() را معرفی مینماید.
//Interface
namespace Interface { public interface ICustomer { void Report(); } }
گام دوم: یک class library به نام MainClass ساخته و با Add Reference کلاس Interface را اضافه نموده، در آن دو کلاس با نام Customer1, Customer2 میسازیم و using Interface را Import مینماییم. هر دو کلاس از ICustomer ارث میبرند و سپس متد Report() را در هر دو کلاس Implement مینماییم.
// Customer1 using System; using Interface; namespace MainClass { public class Customer1 : ICustomer { public void Report() { Console.WriteLine("این گزارش مخصوص مشتری نوع اول است"); } } } //Customer2 using System; using Interface; namespace MainClass { public class Customer2 : ICustomer { public void Report() { Console.WriteLine("این گزارش مخصوص مشتری نوع دوم است"); } } }
گام سوم: یک class library به نام FactoryClass ساخته و با Add Reference کلاس Interface, MainClass را اضافه نموده، در آن یک کلاس با نام clsFactory می سازیم و using Interface, using MainClass را Import مینماییم. پس از آن یک متد با نام getCustomerType ساخته که ورودی آن نوع مشتری از نوع int است و خروجی آن از نوع Interface-ICustomer و بر اساس کد نوع مشتری object را از کلاس Customer1 و یا Customer2 میسازیم و آن را return می نماییم.
//Factory using System; using Interface; using MainClass; namespace FactoryClass { public class clsFactory { static public ICustomer getCustomerType(int intCustomerType) { ICustomer objCust; if (intCustomerType == 1) { objCust = new Customer1(); } else if (intCustomerType == 2) { objCust = new Customer2(); } else { return null; } return objCust; } } }
گام چهارم (آخر): در قسمت UI Client، کد نوع مشتری را از کاربر دریافت کرده و با Add Reference کلاس Interface, FactoryClass را اضافه نموده (دقت نمایید هیچ دسترسی به کلاسهای اصلی وجود ندارد)، و using Interface, using FactoryClass را Import مینماییم. از clsFactory تابع getCustomerType را فراخوانی نموده (به آن کد نوع مشتری را پاس میدهیم) و خروجی آن را که از نوع اینترفیس است به یک object از نوع ICustomer نسبت میدهیم. سپس از این object متد Report را فراخوانی مینماییم. همانطور که از شکل و کدها مشخص است، هیچ رابطه ای بین UI(Client) و کلاسهای اصلی برقرار نیست.
//UI (Client) using System; using FactoryClass; using Interface; namespace DesignPattern { class Program { static void Main(string[] args) { int intCustomerType = 0; ICustomer objCust; Console.WriteLine("نوع مشتری را وارد نمایید"); intCustomerType = Convert.ToInt16(Console.ReadLine()); objCust = clsFactory.getCustomerType(intCustomerType); objCust.Report(); Console.ReadLine(); } } }
این مطلب در ادامهی "آشنایی با الگوی IOC یا Inversion of Control (واگذاری مسئولیت)" میباشد که هر از چندگاهی یک قسمت جدید و یا کاملتر از آن ارائه خواهد شد.
==============
به صورت خلاصه ترزیق وابستگی و یا dependency injection ، الگویی است جهت تزریق وابستگیهای خارجی یک کلاس به آن، بجای استفاده مستقیم از آنها در درون کلاس.
برای مثال شخصی را در نظر بگیرید که قصد خرید دارد. این شخص میتواند به سادگی با کمک یک خودرو خود را به اولین محل خرید مورد نظر برساند. حال تصور کنید که 7 نفر عضو یک گروه، با هم قصد خرید دارند. خوشبختانه چون تمام خودروها یک اینترفیس مشخصی داشته و کار کردن با آنها تقریبا شبیه به یکدیگر است، حتی اگر از یک ون هم جهت رسیدن به مقصد استفاده شود، امکان استفاده و راندن آن همانند سایر خودروها میباشد و این دقیقا همان مطلبی است که هدف غایی الگوی تزریق وابستگیها است. بجای اینکه همیشه محدود به یک خودرو برای استفاده باشیم، بنابر شرایط، خودروی متناسبی را نیز میتوان مورد استفاده قرار داد.
در دنیای نرم افزار، وابستگی کلاس Driver ، کلاس Car است. اگر موارد ذکر شده را بدون استفاده از تزریق وابستگیها پیاده سازی کنیم به کلاسهای زیر خواهیم رسید:
//Person.cs
namespace DependencyInjectionForDummies
{
class Person
{
public string Name { get; set; }
}
}
//Car.cs
using System;
using System.Collections.Generic;
namespace DependencyInjectionForDummies
{
class Car
{
List<Person> _passengers = new List<Person>();
public void AddPassenger(Person p)
{
_passengers.Add(p);
Console.WriteLine("{0} added!", p.Name);
}
public void Drive()
{
foreach (var passenger in _passengers)
Console.WriteLine("Driving {0} ...!", passenger.Name);
}
}
}
//Driver.cs
using System.Collections.Generic;
namespace DependencyInjectionForDummies
{
class Driver
{
private Car _myCar = new Car();
public void DriveToMarket(IList<Person> passengers)
{
foreach (var passenger in passengers)
_myCar.AddPassenger(passenger);
_myCar.Drive();
}
}
}
//Program.cs
using System.Collections.Generic;
using System;
namespace DependencyInjectionForDummies
{
class Program
{
static void Main(string[] args)
{
new Driver().DriveToMarket(
new List<Person>
{
new Person{ Name="Ali" },
new Person{ Name="Vahid" }
});
Console.WriteLine("Press a key ...");
Console.ReadKey();
}
}
}
توضیحات:
کلاس شخص (Person) جهت تعریف مسافرین، اضافه شده؛ سپس کلاس خودرو (Car) که اشخاص را میتوان به آن اضافه کرده و سپس به مقصد رساند، تعریف گردیده است. همچنین کلاس راننده (Driver) که بر اساس لیست مسافرین، آنها را به خودروی خاص ذکر شده هدایت کرده و سپس آنها را با کمک کلاس خودرو به مقصد میرساند؛ نیز تعریف شده است. در پایان هم یک کلاینت ساده جهت استفاده از این کلاسها ذکر شده است.
همانطور که ملاحظه میکنید کلاس راننده به کلاس خودرو گره خورده است و این راننده همیشه تنها از یک نوع خودروی مشخص میتواند استفاده کند و اگر روزی قرار شد از یک ون کمک گرفته شود، این کلاس باید بازنویسی شود.
خوب! اکنون اگر این کلاسها را بر اساس الگوی تزریق وابستگیها (روش تزریق در سازنده که در قسمت قبل بحث شد) بازنویسی کنیم به کلاسهای زیر خواهیم رسید:
//ICar.cs
using System;
namespace DependencyInjectionForDummies
{
interface ICar
{
void AddPassenger(Person p);
void Drive();
}
}
//Car.cs
using System;
using System.Collections.Generic;
namespace DependencyInjectionForDummies
{
class Car : ICar
{
//همانند قسمت قبل
}
}
//Van.cs
using System;
using System.Collections.Generic;
namespace DependencyInjectionForDummies
{
class Van : ICar
{
List<Person> _passengers = new List<Person>();
public void AddPassenger(Person p)
{
_passengers.Add(p);
Console.WriteLine("{0} added!", p.Name);
}
public void Drive()
{
foreach (var passenger in _passengers)
Console.WriteLine("Driving {0} ...!", passenger.Name);
}
}
}
//Driver.cs
using System.Collections.Generic;
namespace DependencyInjectionForDummies
{
class Driver
{
private ICar _myCar;
public Driver(ICar myCar)
{
_myCar = myCar;
}
public void DriveToMarket(IList<Person> passengers)
{
foreach (var passenger in passengers)
_myCar.AddPassenger(passenger);
_myCar.Drive();
}
}
}
//Program.cs
using System.Collections.Generic;
using System;
namespace DependencyInjectionForDummies
{
class Program
{
static void Main(string[] args)
{
Driver driver = new Driver(new Van());
driver.DriveToMarket(
new List<Person>
{
new Person{ Name="Ali" },
new Person{ Name="Vahid" }
});
Console.WriteLine("Press a key ...");
Console.ReadKey();
}
}
}
توضیحات:
در اینجا یک اینترفیس جدید به نام ICar اضافه شده است و بر اساس آن میتوان خودروهای مختلفی را با نحوهی بکارگیری یکسان اما با جزئیات پیاده سازی متفاوت تعریف کرد. برای مثال در ادامه، یک کلاس ون با پیاده سازی این اینترفیس تشکیل شده است. سپس کلاس رانندهی ما بر اساس ترزیق این اینترفیس در سازندهی آن بازنویسی شده است. اکنون این کلاس دیگر نمیداند که دقیقا چه خودرویی را باید مورد استفاده قرار دهد و از وابستگی مستقیم به نوعی خاص از آنها رها شده است؛ اما میداند که تمام خودروها، اینترفیس مشخص و یکسانی دارند. به تمام آنها میتوان مسافرانی را افزود و سپس به مقصد رساند. در پایان نیز یک راننده جدید بر اساس خودروی ون تعریف شده، سپس یک سری مسافر نیز تعریف گردیده و نهایتا متد DriveToMarket فراخوانی شده است.
به این صورت به یک سری کلاس اصطلاحا loosely coupled رسیدهایم. دیگر رانندهی ما وابستهی به یک خودروی خاص نیست و هر زمانی که لازم بود میتوان خودروی مورد استفادهی او را تغییر داد بدون اینکه کلاس راننده را بازنویسی کنیم.
یکی دیگر از مزایای تزریق وابستگیها ساده سازی unit testing کلاسهای برنامه توسط mocking frameworks است. به این صورت توسط این نوع فریمورکها میتوان رفتار یک خودرو را تقلید کرد بجای اینکه واقعا با تمام ریز جرئیات آنها بخواهیم سروکار داشته باشیم (وابستگیها را به صورت مستقل میتوان آزمایش کرد).
Memento یک الگوی طراحی مفید و ساده است که برای ذخیره و بازیابی state یک object استفاده میشود. در بعضی از مقالات از آن به عنوان snapshot نیز یاد شده است! اگر با git کار کرده باشید، این مفهوم را میتوان در git بسیار یافت؛ هر commit به عنوان یک snapshot میباشد که میتوان به صورت مکرر آن را undo کرد و یا مثال خیلی سادهتر میتوان به ctrl+z در سیستم عامل اشاره کرد.
به مثال زیر توجه کنید:
Int temp; Int a=1; temp=a; a=2; . . a=temp;
شما قطعا در برنامه نویسی با کد بالا زیاد برخورد داشتهاید و آنرا به صورت مکرر انجام دادهاید. کد بالا را در قالب یک object بیان میکنیم. به مثال زیر توجه کنید:
int main() { MyClass One = new MyClass(); MyClass Temp = new MyClass(); // Set an initial value. One.Value = 10; One.Name = "Ten"; // Save the state of the value. Temp.Value = One.Value; Temp.Name = One.Name; // Change the value. One.Value = 99; One.Name = "Ninety Nine"; // Undo and restore the state. One.Value = Temp.Value; One.Name = Temp.Name; }
در کد بالا با استفاده از یک temp، شیء مورد نظر را ذخیره کرده و در آخر مجدد دادهها را درون شیء، restore میکنیم.
از مشکلات کد بالا میتوان گفت :
۱- برای هر object باید یک شیء temp ایجاد کنیم.
۲- ممکن است بخواهیم که حالات یک object را بر روی هارد ذخیره کنیم. با روش فوق کدها خیلی پیچیدهتر خواهند شد.
۳- نوشتن کد به این سبک برای پروژههای بزرگ، پیچیده و مدیریت آن سختتر میشود.
پیاده سازی memento
ما این مثال را در قالب یک پروژه NET Core onsole. ایجاد میکنیم. برای این کار یک پوشهی جدید را ایجاد و درون ترمینال دستور زیر را وارد کنید:
dotnet new console
روشهای زیادی برای پیاده سازی memento وجود دارند. برای پیاده سازی memento ابتدا یک abstract class را به شکل زیر ایجاد میکنیم:
abstract class MementoBase { protected Guid mementoKey = Guid.NewGuid(); abstract public void SaveMemento(Memento memento); abstract public void RestoreMemento(Memento memento); }
اگر به کلاس بالا دقت کنید، این کلاس قرار است parent کلاسهای دیگری باشد که داری دو متد SaveMemento و RestoreMemento برای ذخیره و بازیابی و همچنین یک Guid برای نگهداری stateهای مختلف میباشد.
ورودی متدها از نوع memento میباشد. پس کلاس memento را به شکل زیر ایجاد میکنیم:
class Memento { private Dictionary<Guid, object> stateList = new Dictionary<Guid, object>(); public object GetState(Guid key) { return stateList[key]; } public void SetState(Guid key, object newState) { stateList[key] = newState; } public Memento() { } }
در کد بالا با یک Dictionary میتوان هر object را با کلیدش ذخیره کنیم. توجه کنید که value دیکشنری از نوع object میباشد و چون object پدر تمام objectهای دیگر است پس میتوانیم هر نوع دادهای را در آن ذخیره کنیم. تا اینجا، Memento پیاده سازی شده است. میتوان این کار را با جنریکها نیز پیاده سازی کرد.
در ادامه میخواهیم یک کلاس بسازیم و حالتهای مختلف را در آن بررسی کنیم. کلاس زیر را ایجاد کنید:
class ConcreteOriginator : MementoBase { private int value = 0; public ConcreteOriginator(int newValue) { SetData(newValue); } public void SetData(int newValue) { value = newValue; } public void Speak() { Console.WriteLine("My value is " + value.ToString()); } public override void SaveMemento(Memento memento) { memento.SetState(mementoKey, value); } public override void RestoreMemento(Memento memento) { int restoredValue = (int)memento.GetState(mementoKey); SetData(restoredValue); } }
کلاس ConcreteOriginator از کلاس MementoBase ارث بری کرده و دو متد RestoreMemento و SaveMemento را پیاده سازی میکند و همچنین دارای یک مشخصه value میباشد. برای خروجی گرفتن، متد main را به صورت زیر پیاده سازی میکنیم:
static void Main(string[] args) { Memento memento = new Memento(); // Create an originator, which will hold our state data. ConcreteOriginator myOriginator = new ConcreteOriginator("Hello World!", StateType.ONE); ConcreteOriginator anotherOriginator = new ConcreteOriginator("Hola!", StateType.ONE); ConcreteOriginator2 thirdOriginator = new ConcreteOriginator2(7); // Set some state data. myOriginator.Speak(); anotherOriginator.Speak(); thirdOriginator.Speak(); // Save the states into our memento. myOriginator.SaveMemento(memento); anotherOriginator.SaveMemento(memento); thirdOriginator.SaveMemento(memento); // Now change our originators' states. myOriginator.SetData("Goodbye!", StateType.TWO); anotherOriginator.SetData("Adios!", StateType.TWO); thirdOriginator.SetData(99); myOriginator.Speak(); anotherOriginator.Speak(); thirdOriginator.Speak(); // Restore our originator's state. myOriginator.RestoreMemento(memento); anotherOriginator.RestoreMemento(memento); thirdOriginator.RestoreMemento(memento); myOriginator.Speak(); anotherOriginator.Speak(); thirdOriginator.Speak(); Console.ReadKey(); }
Hello World! I'm in state ONE Hola! I'm in state ONE My value is 7 Goodbye! I'm in state TWO Adios! I'm in state TWO My value is 99 Hello World! I'm in state ONE Hola! I'm in state ONE My value is 7
دوره آموزشی Blazor
Welcome to this short introduction to Blazor! This new Microsoft framework uses a unique approach to leverage your existing C# and .NET skills to create single-page applications running in web browsers. The technology that makes this possible is called WebAssembly, an open standard supported directly by current browsers on desktop and mobile platforms. You write C# and Razor code instead of JavaScript, and the compiled app runs natively on the client.
Sample Source Code: https://github.com/DevExpress/blazor-training-samples
Visual Studio 2017 15.5.7 منتشر شد
9.Visual Studio 2017 15.8 منتشر شد
These are the customer-reported issues addressed in 15.8.9:
- Added support for Xcode 10.1 in Visual Studio Tools for Xamarin.
- Updated the Xamarin.Forms template to Xamarin.Forms 3.3.0.
- Update 15.8.6 breaks Installer Projects.
- Internal Compiler error in VS15.8 msc1.cpp line 1518.
- Microsoft Visual Studio 2017 Installer Projects 0.8.8 and VS 15.8.6.
- SFINAE fails to detect matching overloaded function in preview VS preview 3 15.9.0.
- XAML Designer crash on Visual Studio close.
class Visitor { visit(item){} } class BookVisitor extends Visitor { visit(book) { var cost=0; if(book.getPrice() > 50) { cost = book.getPrice()*0.50 } else{ cost = book.getPrice() } console.log("Book name: "+ book.getName() + "\n" + "ID: " + book.getID() + "\n" + "cost: "+ cost); return cost; } } class Book{ constructor(id,name,price){ this.id = id this.name = name this.price = price } getPrice(){ return this.price } getName(){ return this.name } getID(){ return this.id } accept(visitor){ return visitor.visit(this) } } var visitor = new BookVisitor() var book1 = new Book("#1234","lordOftheRings",80) book1.accept(visitor)
class Book{ constructor(id,name,price){ this.id = id this.name = name this.price = price } //code... }
- id
- name
- price
getPrice(){ return this.price } getName(){ return this.name } getID(){ return this.id }
accept(visitor){ return visitor.visit(this) }
class Visitor { visit(item){} }
class BookVisitor extends Visitor { visit(book) { var cost=0; if(book.getPrice() > 50) { cost = book.getPrice()*0.50 } else{ cost = book.getPrice() } console.log("Book name: "+ book.getName() + "\n" + "ID: " + book.getID() + "\n" + "cost: "+ cost); return cost; } }
- زمانیکه نیاز است عملیاتی مشابه، بر روی شیءهای متفاوتی از یک data structure انجام شود.
- زمانیکه نیاز است عملیاتی خاص، بر روی شیءهای متفاوتی از data structure انجام شود.
- زمانیکه میخواهید توسعه پذیری را برای کتابخانهها (libraries) یا فریم ورکها (frameworks) اضافه کنید.