مطالب
C# 7 - Tuple return types and deconstruction
روش‌های زیادی برای بازگشت چندین مقدار از یک متد وجود دارند؛ مانند استفاده‌ی از آرایه‌ها برای بازگشت اشیایی از یک جنس، ایجاد یک کلاس سفارشی با خواص متفاوت و استفاده از پارامترهای out و ref همانند روش‌های متداول در C و ++C. در این بین روش دیگری نیز به نام Tuples از زمان NET 4.0. برای بازگشت چندین شیء با نوع‌های مختلف، ارائه شده‌است که در C# 7 نحوه‌ی تعریف و استفاده‌ی از آن‌ها بهبود قابل ملاحظه‌ای یافته‌است.


Tuple چیست؟

هدف از کار با Tupleها، عدم تعریف یک کلاس جدید به همراه خواص آن، جهت بازگشت بیش از یک مقدار از یک متد، توسط وهله‌ای از این کلاس جدید می‌باشد. برای مثال اگر بخواهیم از متدی، دو مقدار شهر و ناحیه را بازگشت دهیم، یک روش آن، ایجاد کلاس مکان زیر است:
public class Location   
{ 
     public string City { get; set; } 
     public string State { get; set; } 
 
     public Location(string city, string state) 
     { 
           City = city; 
           State = state; 
     } 
}
و سپس، وهله سازی و بازگشت آن:
 var location = new Location("Lake Charles","LA");
اما توسط Tuples، بدون نیاز به تعریف یک کلاس جدید، باز هم می‌توان به همین دو خروجی، دسترسی یافت:
 var location = new Tuple<string,string>("Lake Charles","LA");   
// Print out the address
var address = $"{location.Item1}, {location.Item2}";


مشکلات نوع Tuple در نگارش‌های قبلی دات نت

هرچند Tuples از زمان دات نت 4 در دسترس هستند، اما دارای این کمبودها و مشکلات می‌باشند:
static Tuple<int, string, string> GetHumanData()
{
   return Tuple.Create(10, "Marcus", "Miller");
}
الف) پارامترهای خروجی آن‌ها ثابت و با نام‌هایی مانند Item1، Item2 و امثال آن هستند که در حین استفاده، به علت ضعف نامگذاری، کاربرد آن‌ها دقیقا مشخص نیست و کاملا بی‌معنا هستند:
 var data = GetHumanData();
Console.WriteLine("What is this value {0} or this {1}",  data.Item1, data.Item3);
ب) Reference Type هستند (کلاس هستند) و در زمان وهله سازی، میزان مصرف حافظه‌ی بیشتری را نسبت به Value Types (معادل Tuples در C# 7) دارند.
ج) Tuples در دات نت 4، صرفا یک کتابخانه‌ی اضافه شده‌ی به فریم ورک بوده و زبان‌های دات نتی، پشتیبانی توکاری را از آن‌ها جهت بهبود و یا ساده سازی تعریف آن‌ها، ارائه نمی‌دهند.


ایجاد Tuples در C# 7

برای ایجاد Tuples در سی شارپ 7، از پرانتزها به همراه ذکر نام و نوع پارامترها استفاده می‌شود.
(int x1, string s1) = (3, "one");
Console.WriteLine($"{x1} {s1}");
در مثال فوق، یک Tuple ایجاد شده‌است و در آن مقدار 3 به x1 و مقدار "one" به s1 انتساب داده شده‌اند. به این عملیات deconstruction هم می‌گویند.
دسترسی به این مقادیر نیز همانند متغیرهای معمولی است.

اگر سعی کنیم این قطعه کد را کامپایل نمائیم، با خطای ذیل متوقف خواهیم شد:
 error CS8179: Predefined type 'System.ValueTuple`2' is not defined or imported
برای رفع این مشکل نیاز است بسته‌ی نیوگت ذیل را نیز نصب کرد:
 PM> install-package System.ValueTuple

تعاریف متغیرهای بازگشتی، خارج از پرانتزها هم می‌توانند صورت گیرند:
int x2;
string s2;
(x2, s2) = (42, "two");
Console.WriteLine($"{x2} {s2}");


بازگشت Tuples از متدها

متد ذیل، دو خروجی نتیجه و باقیمانده‌ی تقسیم دو عدد صحیح را باز می‌گرداند:
static (int, int) Divide(int x, int y)
{
   int result = x / y;
   int reminder = x % y;
 
   return (result, reminder);
}
برای این منظور، نوع خروجی متد به صورت (int, int) و همچنین مقدار بازگشتی نیز به صورت یک Tuple از نتیجه و باقیمانده‌ی تقسیم، تعریف شده‌است.
در ادامه نحوه‌ی استفاده‌ی از این متد را مشاهده می‌کنید:
 (int result, int reminder) = Divide(11, 3);
Console.WriteLine($"{result} {reminder}");

در اینجا امکان استفاده‌ی از var نیز برای تعریف نوع متغیرهای دریافتی از یک Tuple نیز وجود دارد و کامپایلر به صورت خودکار نوع آن‌ها را بر اساس نوع خروجی tuple مشخص می‌کند:
 (var result1, var reminder1) = Divide(11, 3);
Console.WriteLine($"{result1} {reminder1}");
و یا حتی چون نوع var پارامترها در اینجا یکی است و در هر دو حالت به int اشاره می‌کند، می‌توان این var را در خارج از پرانتز هم قرار داد:
 var (result1, reminder1) = Divide(11, 3);

و یا برای نمونه متد GetHumanData دات نت 4 ابتدای بحث را به صورت ذیل می‌توان در C# 7 بازنویسی کرد:
static (int, string, string) GetHumanData()
{
   return (10, "Marcus", "Miller");
}
و سپس به نحو واضح‌تری از آن استفاده نمود؛ بدون استفاده‌ی اجباری از Item1 و غیره (هرچند هنوز هم می‌توان از آن‌ها استفاده کرد):
 (int Age, string FirstName, string LastName) results = GetHumanData();
Console.WriteLine(results.Age);
Console.WriteLine(results.FirstName);
Console.WriteLine(results.LastName);


پشت صحنه‌ی Tuples در C# 7

همانطور که عنوان شد، برای اینکه بتوانید قطعه کدهای فوق را کامپایل کنید، نیاز به بسته‌ی نیوگت System.ValueTuple است. در حقیقت کامپایلر خروجی متد فوق را به نحو ذیل تفسیر می‌کند:
 ValueTuple<int, int> tuple1 = Divide(11, 3);
برای مثال قطعه کد
 (int, int) n = (1,1);
System.Console.WriteLine(n.Item1);
توسط کامپایلر به قطعه کد ذیل ترجمه می‌شود:
 ValueTuple<int, int> n = new ValueTuple<int, int>(1, 1);
System.Console.WriteLine(n.Item1);
- برخلاف نگارش‌های پیشین دات نت که Tuples در آن‌ها reference type بودند، این ValueTuple یک struct است و به همین جهت سربار تخصیص حافظه‌ی کمتری را به همراه داشته و از لحاظ کارآیی و میزان مصرف حافظه بهینه‌تر عمل می‌کند.
- همچنین در اینجا محدودیتی از لحاظ تعداد پارامترهای ذکر شده‌ی در یک Tuple وجود ندارد.
 (int,int,int,int,int,int,int,(int,int))
در اینجا هم مانند قبل (دات نت 4) 8 آیتم را می‌توان تعریف کرد؛ اما چون آخرین آیتم ValueTuple تعریف شده نیز یک Tuple است، در عمل محدودیتی از نظر تعداد پارامتر نخواهیم داشت.


مفهوم Tuple Literals

همانند نگارش‌های پیشین دات نت، خروجی یک Tuple را می‌توان به یک متغیر از نوع var و یا ValueType نیز نسبت داد:
 var tuple2 = ("Stephanie", 7);
Console.WriteLine($"{tuple2.Item1}, {tuple2.Item2}");
در این حالت برای دسترسی به مقادیر Tuple همانند قبل باید از فیلدهای Item1 و Item2 و ... استفاده کرد.
به علاوه در سی شارپ 7  می‌توان برای اعضای یک Tuple نام نیز تعریف کرد که به آن‌ها Tuple literals گویند:
 var tuple3 = (Name: "Matthias", Age: 6);
Console.WriteLine($"{tuple3.Name} {tuple3.Age}");
در این حالت زمانیکه Tuple به یک متغیر از نوع var نسبت داده می‌شود، می‌توان به خروجی آن بر اساس نام‌های اعضای Tuple، بجای ذکر Item1 و ... دسترسی یافت که خوانایی بیشتری دارند.

و یا هنگام تعریف نوع خروجی، می‌توان نام پارامترهای متناظر را نیز ذکر کرد که به آن named elements هم می‌گویند:
static (int radius, double area) CalculateAreaOfCircle(int radius)
{
   return (radius, Math.PI * Math.Pow(radius, 2));
}
و نمونه‌ای از کاربرد آن به صورت ذیل است که در اینجا خروجی Tuple صرفا به یک متغیر از نوع var نسبت داده شده‌است و توسط نام پارامترهای خروجی متد، می‌توان به اعضای Tuple دسترسی یافت.
 var circle = CalculateAreaOfCircle(2);
Console.WriteLine($"A circle of radius, {circle.radius}," +
 $" has an area of {circle.area:N2}.");


مفهوم Deconstructing Tuples

مفهوم deconstruction که در ابتدای بحث عنوان شد صرفا مختص به Tuples نیست. در C# 7 می‌توان مشخص کرد که چگونه یک نوع خاص، به اجزای آن تجزیه شود. برای مثال کلاس شخص ذیل را درنظر بگیرید:
class Person
{
    private readonly string _firstName;
    private readonly string _lastName;
 
    public Person(string firstname, string lastname)
    {
        _firstName = firstname;
        _lastName = lastname;
    }
 
    public override String ToString() => $"{_firstName} {_lastName}";
 
    public void Deconstruct(out string firstname, out string lastname)
    {
        firstname = _firstName;
        lastname = _lastName;
    }
}
- در اینجا یک متد جدید را به نام Deconstruct مشاهده می‌کنید. کار این متد جدید که توسط کامپایلر استفاده خواهد شد، ارائه‌ی روشی است برای «تجزیه‌ی» یک نوع، به یک Tuple‌. متد Deconstruct تعریف شده‌ی در اینجا توسط پارامترهایی از نوع out، دو خروجی را مشخص می‌کنند. امکان تعریف این متد ویژه، به صورتیکه یک Tuple را بازگرداند، وجود ندارد.
- علت تعریف این دو خروجی هم به constructor و یا سازنده‌ی کلاس بر می‌گردد که دو ورودی را دریافت می‌کند. اگر یک کلاس چندین سازنده داشته باشد، به همان تعداد می‌توان متد Deconstruct تعریف کرد؛ به همراه خروجی‌هایی متناظر با نوع پارامترهای سازنده‌ها.
- علت استفاده‌ی از نوع خروجی out نیز این است که در #C نمی‌توان چندین overload را صرفا بر اساس نوع خروجی‌های متفاوت متدها تعریف کرد.
- متد Deconstruct به صورت خودکار در زمان تجزیه‌ی یک شیء به یک tuple فراخوانی می‌شود. در مثال زیر، شیء p1 به یک Tuple تجزیه شده‌است و این تجزیه بر اساس متد Deconstruct این کلاس مفهوم پیدا می‌کند:
 var p1 = new Person("Katharina", "Nagel");
(string first, string last) = p1;
Console.WriteLine($"{first} {last}");


امکان تعریف متد Deconstruct‌، به صورت یک متد الحاقی

روش اول تعریف متد ویژه‌ی Deconstruct را در مثال قبل، در داخل کلاس اصلی مشاهده کردید. روش دیگر آن، استفاده‌ی از متدهای الحاقی است که در این مورد خاص نیز مجاز است:
public class Rectangle
{
    public Rectangle(int height, int width)
    {
        Height = height;
        Width = width;
    }
 
    public int Width { get; }
    public int Height { get; }
}
 
public static class RectangleExtensions
{
    public static void Deconstruct(this Rectangle rectangle, out int height, out int width)
    {
        height = rectangle.Height;
        width = rectangle.Width;
    }
}
در اینجا کلاس مستطیل دارای سازنده‌ای با دو پارامتر است؛ اما متد Deconstruct آن به صورت یک متد الحاقی، خارج از کلاس اصلی تعریف شده‌است.
اکنون امکان انتساب وهله‌ای از این کلاس به یک Tuple وجود دارد:
 var r1 = new Rectangle(100, 200);
(int height, int width) = r1;
Console.WriteLine($"height: {height}, width: {width}");


امکان جایگزین کردن Anonymous types با Tuples

قطعه کد ذیل را در نظر بگیرید:
List<Employee> allEmployees = new List<Employee>()
{
  new Employee { ID = 1L, Name = "Fred", Salary = 50000M },
  new Employee { ID = 2L, Name = "Sally", Salary = 60000M },
  new Employee { ID = 3L, Name = "George", Salary = 70000M }
};
var wellPaid =
  from oneEmployee in allEmployees
  where oneEmployee.Salary > 50000M
  select new { EmpName = oneEmployee.Name,
               Income = oneEmployee.Salary };
در اینجا خروجی LINQ تهیه شده یک لیست anonymously typed است؛ با محدودیت‌هایی مانند عدم امکان استفاده‌ی از خروجی آن در سایر اسمبلی‌ها. این نوع‌های ویژه تنها محدود هستند به همان اسمبلی که در آن تعریف می‌شوند. اما در C# 7 می‌توان قطعه کد فوق را با Tuples به صورت ذیل بازنویسی کرد که این محدودیت‌ها را هم ندارد (با هدف به حداقل رساندن تعداد ViewModel‌های تعریفی یک برنامه):
var wellPaid =
  from oneEmployee in allEmployees
  where oneEmployee.Salary > 50000M
  orderby oneEmployee.Salary descending
  select (EmpName: oneEmployee.Name,
          Income: oneEmployee.Salary);
var highestPaid = wellPaid.First().EmpName;


سایر کاربردهای Tuples

از Tuples صرفا برای تعریف چندین خروجی از یک متد استفاده نمی‌شود. در ذیل نحوه‌ی استفاده‌ی از آن‌ها را جهت تعریف کلید ترکیبی یک شیء دیکشنری و یا استفاده‌ی از آن‌ها را در آرگومان جنریک یک متد async هم مشاهده می‌کنید:
public Task<(int index, T item)> FindAsync<T>(IEnumerable<T> input, Predicate<T> match)
{
   var dictionary = new Dictionary<(int, int), string>();
   throw new NotSupportedException();
}
مطالب
چند نکته‌ی کاربردی در #C
استفاده از Tuple‌ها جهت مقدار برگشتی یک متد

اکثر مواقع برنامه نویسان برای بازگشت چند مقدار توسط یک متد، به روش‌هایی مثل تعریف کلاس‌های POCO یا پارامترهایی از نوع out متوسل می‌شوند. به وسیله‌ی Tuple‌ها می‌توان چند مقدار مختلف را به عنوان خروجی متد بازگشت داد:
private Tuple<string, string, int> GetPersonInfo()
{
     return new Tuple<string, string, int>("Steve", "Jobs", 56);
}
همچنین از Tuple‌ها می‌توان برای پاس دادن یکباره پارامترها به متد استفاده کرد و در مواقعی مانند ارسال پارامتر به Thread‌ها که در حالت عادی یک پارامتر را به عنوان ورودی قبول می‌کنند، کاربردی خواهند بود.


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

اکثر برنامه نویسان، در متدهایی که لیستی از مقادیر را بازگشت می‌دهند، از یک متغییر موقتی استفاده می‌کنند:
private IEnumerable<int> GetNumbers()
{
   var result = new List<int>();

   for (int i = 0; i <= 100; i++)
      result.Add(i);

   return result;
}
اما باید دانست که الزاما نیازی به انجام این کار نیست و به وسیله‌ی کلیدواژه‌ی yield می‌توان مقادیر را همزمان با تولید آنها در بدنه متد به عنوان خروجی متد بازگشت داد و به این ترتیب به مصرف حافظه‌ی کمتری رسید:
private IEnumerable<int> GetNumbers()
{
   for (int i = 0; i <= 100; i++)
   {
        yield return i;
   }
}

ملزم کردن نوع پایه یک کلاس Generic به رعایت قوانین پیاده سازی خاص

Generic‌ها میتوانند عملکرد یکسانی را برای نوع‌های داده‌ای متفاوت، پیاده سازی کنند. با توجه به ماهیت Generic‌ها ممکن است در سناریوهایی لازم باشد تا نوع داده‌ی اولیه‌ای که قرار است Generic پیاده سازی شود، از قوانین پیاده سازی خاصی پیروی کند. به صورت زیر می‌توان نوع پایه‌ی یک Generic را ملزم به رعایت قوانین خاص پیاده سازی به واسطه یک Interface کرد:
public interface ICar
{
   string GetName();
   string GetManufacturerCompany();
}

private class GenricClass<T> where T : ICar
{
}
نمونه‌ی استفاده:
public class Audi : ICar
{
   public string GetName()
   {
      throw new NotImplementedException();
   }

   public string GetManufacturerCompany()
   {
      throw new NotImplementedException();
   }
}

private static void Main(string[] args)
{
   var invalidTest = new GenricClass<int>();
   var validTest = new GenricClass<Audi>();
}
نظرات مطالب
مدیریت AccessViolationException در برنامه‌های دات نت 4 به بعد
با سلام؛ من یه پروژه با WPF نوشتم اما یه ایراد داره و اونم اینه که مثلا فرم1 رو 20 بار اجرا می‌کنی خطا نمی‌ده اما بار 21 ام برنامه کرش میکنه و اصلا نمیشه catch کرد. متن خطا در Log ویندوز اینه
Error 01 :
Application: MyWPFApp.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: exception code c0000005, exception address 77D52239
 
Error 02 :
Faulting application name: MyWPFApp.exe, version: 1.0.0.0, time stamp: 0x52d550ac
Faulting module name: ntdll.dll, version: 6.1.7601.17514, time stamp: 0x4ce7b96e
Exception code: 0xc0000005
Fault offset: 0x00032239
Faulting process id: 0xa28
Faulting application start time: 0x01cf113ae6813d88
Faulting application path: R:\Source\MyWPFApp\bin\Debug\MyWPFApp.exe
Faulting module path: C:\Windows\SYSTEM32\ntdll.dll
Report Id: 460eda62-7d33-11e3-a572-ac220bc99cf8
 
Information :
Fault bucket , type 0
Event Name: APPCRASH
Response: Not available
Cab Id: 0
 
Problem signature:
P1: MyWPFApp.exe
P2: 1.0.0.0
P3: 52d550ac
P4: ntdll.dll
P5: 6.1.7601.17514
P6: 4ce7b96e
P7: c0000005
P8: 00032239
P9:
P10:
 
Attached files:
C:\Users\Administrator\AppData\Local\Temp\WERE9B3.tmp.WERInternalMetadata.xml
C:\Users\Administrator\AppData\Local\Temp\WER16AC.tmp.appcompat.txt
C:\Users\Administrator\AppData\Local\Temp\WER18A1.tmp.hdmp
C:\Users\Administrator\AppData\Local\Temp\WER3BFA.tmp.mdmp
 
These files may be available here:
C:\Users\Administrator\AppData\Local\Microsoft\Windows\WER\ReportQueue\AppCrash_MyWPFApp.exe_125fc667a69fcc31c463a5e1b4032657c4ce830_cab_0ac03d3e
 
Analysis symbol:
Rechecking for solution: 0
Report Id: 460eda62-7d33-11e3-a572-ac220bc99cf8
اشتراک‌ها
TypeScript 4.0 Beta منتشر شد

Now let’s take a look at what’s in store for TypeScript 4.0!

Variadic Tuple Types
Labeled Tuple Elements
Class Property Inference from Constructors
Short-Circuiting Assignment Operators
unknown on catch Clauses
Custom JSX Factories
Speed Improvements in build mode with --noEmitOnError
--incremental with --noEmit
Editor Improvements
  /** @deprecated */ Support
  Partial Editing Mode at Startup
  Smarter Auto-Imports
Breaking Changes 

TypeScript 4.0 Beta منتشر شد
مطالب
پردازش فایل‌های XML با استفاده از jQuery

فرض کنید مثال دریافت اطلاعات API فیدبرنر را بخواهیم با استفاده از jQuery پیاده سازی کنیم، یعنی امکان برنامه نویسی سمت سرور را نداریم و می‌خواهیم با استفاده از جاوا اسکریپت، تعداد مشترکین فید یک سایت را نمایش دهیم.
برای مثال آدرس دریافت اطلاعات مربوط به API فیدبرنر وبلاگ جاری به صورت زیر است:

و در حالت کلی :
http://api.feedburner.com/awareness/1.0/GetFeedData?uri=<feeduri>

که حاصل آن برای مثال یک فایل XML با فرمت زیر می‌باشد:

<rsp stat="ok">
<feed id="fhphjt61bueu08k93ehujpu234" uri="vahidnasiri">
<entry date="2009-01-23" circulation="153" hits="276" reach="10"/>
</feed>
</rsp>

همانطور که مطلع هستید چند روزی است که jQuery 1.3.1 ارائه شده است. جهت استفاده از آخرین نگارش موجود آن تا این زمان، می‌توان از گوگل به عنوان هاست این کتابخانه به صورت زیر استفاده کرد:

<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js' type='text/javascript'></script>

نحوه خواندن مقدار circulation فایل xml ذخیره شده بر روی کامپیوتر:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>FeedBurner API</title>
<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js' type='text/javascript'>
</script>
<script type="text/javascript">
function parseXml(xml){
//find every entry and print the circulation
$(xml).find("entry").each(function(){
$("#output").append($(this).attr("circulation"));
});
}

$(document).ready(function(){
$.ajax({
type: "GET",
url: "GetFeedData_local.xml",
dataType: "xml",
success: parseXml
});
});
</script>
</head>
<body>
<div dir="rtl" style="font-family:tahoma; font-size:12px;">
تعداد مشترکین تغذیه خبری سایت:
<div id="output">
</div>
</div>
</body>
</html>

با استفاده از قابلیت Ajax کتابخانه jQuery ، اطلاعات فایل محلی GetFeedData_local.xml دریافت شده و محتوای آن به تابع parseXml پاس می‌شود (توسط قسمت success). سپس در این تابع تمام تگ‌های entry یافت شده و مقدار circulation آن‌ها به یک div با ID معادل output اضافه می‌شود.
مثال فوق در مورد خواندن اطلاعات از یک فایل xml می‌تواند برای مثال این کاربرد را در یک سایت داشته باشد:
نمایش اتفاقی سخن روز یا سخن بزرگان و امثال آن بدون برنامه نویسی سمت سرور جهت انجام این کار از یک فایل xml تهیه شده، بدون نیاز به استفاده از دیتابیس خاصی.

تا اینجای کار مشکلی نیست. اما همانطور که در مطلب مقابله با حملات CSRF نیز ذکر شد، مرورگرهای جدید امکان ارسال یا دریافت اطلاعات به صورت Ajax را بین سایت‌ها ممنوع کرده‌اند (ماجرا هم از آنجا شروع شد که یکبار جی‌میل این باگ امنیتی را داشته است). بنابراین اگر شما بجای url قسمت Ajax فوق، آدرس سایت فید برنر را قرار دهید با خطای زیر متوقف خواهید شد:

Access to restricted URI denied

تمام موارد دیگری هم که در jQuery برای دریافت اطلاعات از یک فایل یا url موجود است (مثلا تابع load یا get و امثال آن) فقط به سایت جاری و دومین جاری باید ختم شوند در غیر اینصورت توسط مرورگرهای جدید متوقف خواهند شد.

مطالب
آموزش فریم ورک Vuetify قسمت دوم - UI Components بخش اول

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

یک کامپوننت در واقع از دو بخش تشکیل شده‌است:

1 - اول اینکه چگونه به نظر می‌رسد ( UI ).

2 – دوم اینکه چگونه کار میکند ( UX ).

این عناصر رابط ( component ) شامل :

Input Controls : check boxes, radio buttons, drop down lists, list boxes, buttons, toggles, text fields, date field

Navigational Components : breadcrumb, slider, search field, pagination, slider, tags, icons

Informational Components : tool tips, icons, progress bar, notifications, message boxes, modal windows

Containers : accordion 

اما باید توجه داشت که فقط به این موارد محدود نمی‌شوند.

در این قسمت به طور مختصر با این دست از کامپوننت‌ها ( UI Component ) آشنا می‌شویم. 


کامپوننت v-alert 

کامپوننت V-Alert برای انتقال اطلاعات مهم به کاربر مورد استفاده قرار می‌گیرد. این کامپوننت چهار نوع اطلاعات را به کاربر گوشزد می‌کند که شامل موفقیت‌ها، اطلاعات، هشدارها و خطاها می‌باشد.

هشدارها می‌توانند یک رنگ خاص را داشته باشند که به طور پیش فرض نمایش داده نمی‌شوند. 

در مثال پایین، کامپوننت v-alert شامل دو مقدار است که برای آن تنظیم شده‌است. مقدار (value) که شامل یک مقدار Boolean است و مقدار (type) که مشخص کننده نوع هشدار است (موفقیت ، اطلاعات ، هشدار و خطا).

در قطعه کد پایین، این چهار نوع اطلاعات قابل نمایش به کاربر مشخص شده‌اند:

<div id="app">
  <v-app id="inspire">
    <div>
      <v-alert :value="true" type="success">
        This is a success alert.
      </v-alert>
  
      <v-alert :value="true" type="info">
        This is a info alert.
      </v-alert>
  
      <v-alert :value="true" type="warning">
        This is a warning alert.
      </v-alert>
  
      <v-alert :value="true" type="error">
        This is a error alert.
      </v-alert>
    </div>
  </v-app>
</div>



برای کامپوننت V-Alert می‌توان properties‌های مختلفی را مشخص نمود که از جمله آنها می‌توان به موارد زیر اشاره کرد:

Color : به وسیله این property می‌توان رنگ پیغام را مشخص نمود. هم به وسیله نام رنگ میتوان رنگ مورد نظر را مشخص کرد و هم به وسیله‌ی کد RGB این کار را انجام داد. dismissible : این تنظیم مشخص می‌کند که پیغام، قابلیت بسته شدن را دارد یا خیر که حاوی یک مقدار Boolean است.

icon : مشخص کننده یک نماد خاص است که درون جعبه پیغام قرار می‌گیرد.

type :  مشخص کننده نوع پیام است که پیشتر در مورد آن توضیح داده شد. 


کامپوننت v-avatar 

کامپوننت v-avatar برای تغییر اندازه تصاویر مورد استفاده قرار می‌گیرد که معمولا جهت نمایش عکس پروفایل استفاده می‌شود.

طریقه استفاده :

avatar، دارای یک اندازه‌ی پویا است که می‌تواند برای هر وضعیتی تغییر کند.

برای این کامپوننت سه properties قابل تنظیم است:

color : به وسیله این property می‌توان رنگ دلخواهی را برای آواتار مشخص نمود. هم به وسیله نام رنگ می‌توان رنگ مورد نظر را مشخص کرد و هم به وسیله کد RGB این کار را صورت داد.

size : به طور پیش‌فرض برای avatar، سایز 48 تنظیم شده‌است که می‌توان این میزان را کم و یا زیاد کرد.

tile : همانند border radius در css عمل می‌کند. با تنظیم این گزینه میتوانیم یک آواتار گرد داشته باشیم.


کامپوننت v-badge

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

این کامپوننت نیز properties خاص خود را دارد که از جمله آن می‌توان به color , left , mode , overlab  و غیره اشاره کرد.

قطعه کد پایین نشان دهنده چگونگی عملکرد این کامپوننت است:

<div id="app">
  <v-app id="inspire">
    <div>
      <v-badge color="purple" left overlap>
        <template v-slot:badge>
          <v-icon dark small>
            done
          </v-icon>
        </template>
        <v-icon color="grey lighten-1" large>
          account_circle
        </v-icon>
      </v-badge>
        <v-badge overlap color="orange">
        <template v-slot:badge>
          <v-icon dark small>
            notifications
          </v-icon>
        </template>
        <v-icon large color="grey darken-1">
          account_box
        </v-icon>
      </v-badge>
    </div>
  </v-app>
</div>

نتیجه قطعه کد بالا بدین ترتیب است:


کامپوننت v-bottom-nav 

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

به وسیله این کامپوننت امکان انتقال از یک بخش از صفحه به بخشی دیگر امکان پذیر می‌شود. 

این کامپوننت نیز properties خاص خود را دارد که از جمله آن می‌توان به active-sync (برای نشان دادن فعال یا غیر فعال بودن گزینه انتخاب شده)، fixed ( برای مشخص کردن موقعیت کامپوننت در صفحه) و موارد دیگر اشاره کرد.

تقسیم بندی اجزاء این کامپوننت به شرح زیر است:

1 - محل قرار گیری کامپوننت

2- آیکن غیر فعال

3- برچسب غیر فعال

4 - آیکن فعال

5- برچسب فعال

قطعه کد پایین نشان دهنده چگونگی یک bottom navbar است:

<div id="app">
  <v-app id="inspire">
    <v-card height="200px" flat>
      <div>
        Active: {{ bottomNav }}   // 
      </div>
      <v-bottom-nav :active.sync="bottomNav" :value="true" absolute color="transparent">
        <v-btn color="teal" flat value="recent">
          <span>Recent</span>
          <v-icon>history</v-icon>
        </v-btn>
  
        <v-btn color="teal" flat value="favorites">
          <span>Favorites</span>
          <v-icon>favorite</v-icon>
        </v-btn>
  
        <v-btn color="teal" flat value="nearby">
          <span>Nearby</span>
          <v-icon>place</v-icon>
        </v-btn>
      </v-bottom-nav>
    </v-card>
  </v-app>
</div>



کامپوننت v-btn  

این کامپوننت برای ایجاد یک دکمه چه به صورت متن و یا آیکن مورد استفاده قرار میگیرد. دکمه‌ها به کاربران این امکان را می‌دهند تا اقداماتی را انجام دهند و انتخاب‌های خود را تنها با یک کلیک انجام دهند.

از دکمه‌ها ممکن است در جاهای مختلف صفحه به خصوص در دیالوگ باکس‌ها، فرمها و ابزارها مورد استفاده قرار گیرد. 

کامپوننت v-btn نیز مانند سایر کامپوننت‌ها تنظیمات خاص خود را دارد که از جمله آن می‌توان به کوچکی و بزرگی دکمه، فعال یا غیر فعال بودن دکمه، نوع متن یا آیکن بودن دکمه اشاره نمود. 

حالت‌های مختلفی از دکمه‌ها وجود دارند که میتوانند به بهتر شدن UI برنامه ما کمک کنند. برای مثال می‌توان به موارد زیر اشاره کرد:

button drop-down variants : دکمه‌های کرکره‌ای که معمولا برای نظم و کم جا بودن در صفحه مورد استفاده قرار می‌گیرند.

icons : آیکن‌ها می‌توانند برای محتوای اصلی یک دکمه مورد استفاده قرار بگیرند تا ظاهر زیباتری را به دکمه ما بدهند.

floating : این دکمه‌ها حالت آیکن را دارند؛ با این تفاوت که آیکن مورد نظر، درون یک محتوا قرار می‌گیرد.

loaders : به وسیله این دکمه‌ها می‌توان کاربر را متوجه انجام یک پردازش نمود. به صورت پیشفرض بعد از فشردن این نوع دکمه‌ها محتوای دکمه فشرده شده تغییر ظاهر داده و به شکل یک دایره در حال چرخش در می‌آید. البته می‌توان این پیشفرض را به حالت‌های دیگری نیز تغییر داد.

round : این نوع دکمه‌ها دقیقا کارآیی دکمه‌های معمولی را دارند؛ با این تفاوت که این دکمه‌ها دارای لبه‌هایی گرد هستند.

یک نمونه از ایجاد انواع دکمه‌ها در زیر آمده است:

<div id="app">
  <v-app id="inspire">
    <div>
      <v-btn color="success">Success</v-btn>
      <v-btn color="error">Error</v-btn>
      <v-btn color="warning">Warning</v-btn>
      <v-btn color="info">Info</v-btn>
    </div>
  </v-app>
</div>




کامپوننت v-calendar

یکی از کامپوننت‌هایی که به تازگی به vuetify اضافه شده است، کامپوننت تقویم یا v-calendar است. از این کامپوننت برای نمایش تاریخ، روز، هفته، ماه و سال استفاده می‌شود. یک تقویم دارای یک نوع و یک مقدار است که تعیین می‌کند چه نوع تقویمی، در طول چه مدت زمانی نمایش داده شود.

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

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

weekly : می‌توان یک تقویم هفتگی را ایجاد نمود و رخدادهای هفتگی را برای آن تنظیم کرد.

نمونه ایجاد یک تقویم در پایین آمده است:

<div id="app">
  <v-app id="inspire">
    <v-layout wrap>
      <v-flex xs12>
        <v-sheet height="500">
          <v-calendar ref="calendar" v-model="start" :type="type" :end="end" color="primary">
          </v-calendar>
        </v-sheet>
      </v-flex>
  
      <v-flex sm4 xs12>
        <v-btn @click="$refs.calendar.prev()">
          <v-icon dark left>
            keyboard_arrow_left
          </v-icon>
          Prev
        </v-btn>
      </v-flex>
      <v-flex sm4 xs12>
        <v-select v-model="type" :items="typeOptions" label="Type">
        </v-select>
      </v-flex>
      <v-flex sm4 xs12>
        <v-btn @click="$refs.calendar.next()">
          Next
          <v-icon right dark>
            keyboard_arrow_right
          </v-icon>
        </v-btn>
      </v-flex>
    </v-layout>
  </v-app>
</div>
js قطعه کد
new Vue({
  el: '#app',
  data: () => ({
    type: 'month', //مشخص کننده نوع تقویم که در اینجا تقویم به صورت ماهانه است
    start: '2019-01-01',
    end: '2019-01-06',
    typeOptions: [
      { text: 'Day', value: 'day' },
      { text: '4 Day', value: '4day' },
      { text: 'Week', value: 'week' },
      { text: 'Month', value: 'month' },
      { text: 'Custom Daily', value: 'custom-daily' },
      { text: 'Custom Weekly', value: 'custom-weekly' }
    ]
  })
})





نظرات مطالب
کار با Docker بر روی ویندوز - قسمت دوم - نصب Docker
سلام، 
من Docker ورژن 2.4 را روی Windows 10 Enterprise LTSC ورژن 1809 نصب کردم، متاسفانه پیش فرض روی Container Linux قرار می‌گیره، هر وقت بخوام Switch کنم روی Container Windows با خطا مواجه می‌شم، خطایی که در Event Viewer ویندوز می‌بینم، به شرح زیر :
failed to start daemon: Error initializing network controller: Error creating default network: failed during hnsCallRawResponse: hnsCall failed in Win32: There are no more endpoints available from the endpoint mapper. (0x6d9) 
مشخصات کامپیوتر من، 
Ram: 32 G
CPU: 7i-8565U
مشخصات داکر:
Client: Docker Engine - Community
 Cloud integration  0.1.18
 Version:           19.03.13
 API version:       1.40
 Go version:        go1.13.15
 Git commit:        4484c46d9d
 Built:             Wed Sep 16 17:00:27 2020
 OS/Arch:           windows/amd64
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          19.03.13
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.13.15
  Git commit:       4484c46d9d
  Built:            Wed Sep 16 17:07:04 2020
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          v1.3.7
  GitCommit:        8fba4e9a7d01810a393d5d25a3621dc101981175
 runc:
  Version:          1.0.0-rc10
  GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683 
مطالب
کوئری نویسی در EF Core - قسمت دوم - کوئری‌های ساده
پس از تشکیل ساختار بانک اطلاعاتی و مقدار دهی اولیه‌ی آن در قسمت قبل، در ادامه به بررسی نحوه‌ی انجام تعدادی کوئری‌های ساده و ابتدایی با EF Core خواهیم پرداخت. در قسمت‌های بعدی حالت‌های پیچیده‌تری را بررسی می‌کنیم.


مثال 1: تمام اطلاعات یک جدول را دریافت کنید.

هدف دریافت تمام اطلاعات جدول facilities است.


برای انجام اینکار فقط کافی‌است بر روی DbSet متناظر با آن، متد ToList فراخوانی شود:
var facilities = context.Facilities.ToList();
حاصل آن، کوئری زیر خواهد بود که در آن، تمام ستون‌های جدول Facilities به صورت خودکار قید می‌شوند:


یک نکته: به فراخوانی متد ToList، اصطلاحا materialization گفته می‌شود و هدف آن تبدیل یک IQueryable، به یک IEnumerable است. اطلاعات بیشتر


مثال 2: اطلاعات ستون‌های خاصی از یک جدول را دریافت کنید.

می‌خواهیم لیست نام امکانات مجموعه را به همراه هزینه‌ی مرتبط با آن‌ها، نمایش دهیم:
var facilities = context.Facilities.Select(x =>
                    new
                    {
                        x.Name,
                        x.MemberCost
                    }).ToList();
برای انتخاب ستون‌هایی خاص از یک جدول، نیاز است از متد Select استفاده کرد و سپس نام دقیق آن‌ها را ذکر نمود. در غیراینصورت همانند مثال1، تمام ستون‌ها بازگشت داده می‌شوند. در اینجا خروجی حاصل، یک anonymous list است که می‌توان آن‌را با یک کلاس و یا حتی یک tuple نیز جایگزین کرد.



مثال 3: نحوه‌ی بازگشت ردیف‌ها را کنترل کنید.

چگونه می‌توان لیست امکاناتی را بازگشت داد که برای کاربران رایگان نیستند؟
var facilities = context.Facilities.Where(x => x.MemberCost > 0).ToList();
برای فیلتر کردن ردیف‌هایی خاص می‌توان از متد Where استفاده کرد. در اینجا امکان نوشتن شرط مدنظر وجود دارد که به آن predicate هم گفته می‌شود و می‌تواند ترکیبی از چندین شرط نیز باشد. در این کوئری چون از متد Select استفاده نشده‌است، تمام ستون‌های جدول بازگشت داده می‌شوند:



مثال 4: نحوه‌ی بازگشت ردیف‌ها را کنترل کنید؛ قسمت دوم.

چگونه می‌توان لیست امکاناتی را بازگشت داد که برای کاربران رایگان نیستند و همچنین هزینه‌ی آن‌ها، 1/50 ام هزینه‌ی نگهداری ماهیانه‌ی آن‌ها است؟ خروجی این کوئری باید تنها به همراه ستون‌های FacId, Name, MemberCost, MonthlyMaintenance باشد.
var facilities = context.Facilities.Where(x => x.MemberCost > 0
                                                            && x.MemberCost < (x.MonthlyMaintenance / 50))
                                                    .Select(x =>
                                                        new
                                                        {
                                                            x.FacId,
                                                            x.Name,
                                                            x.MemberCost,
                                                            x.MonthlyMaintenance
                                                        }).ToList();


در این مثال نحوه‌ی ترکیب چند شرط را با هم در قسمت Where، مشاهده می‌کنید و همچنین با استفاده از متد Select، تعداد ستون‌های بازگشتی نیز کنترل شده‌اند.


مثال 5: جستجوهای ساده‌ی رشته‌ای

لیستی از امکاناتی را تهیه کنید که واژه‌ی «Tennis» در نام آن‌ها بکار رفته‌است.
var facilities = context.Facilities.Where(x => x.Name.Contains("Tennis")).ToList();
یک چنین جستجو‌هایی را می‌توان توسط متد Contains انجام داد که در EF-Core، خروجی زیر را تولید می‌کند:



مثال 6: ردیف‌هایی را که با چندین مقدار ممکن تطابق دارند، بازگشت دهید.

چگونه می‌توان امکانات دارای ID مساوی 1 و 5 را بازگشت داد؟ برای اینکار از ترکیب شرط‌ها با استفاده از OR استفاده نکنید.
int[] ids = { 1, 5 };
var facilities = context.Facilities.Where(x => ids.Contains(x.FacId)).ToList();
یک روش حل این مساله، رسیدن به یک کوئری دارای where facid = 1 or facid = 5 است. اگر تعداد این IDها بیشتر شد، روش Where In که بر روی یک لیست از آن‌ها کار می‌کند، مرسوم‌تر است که نحوه‌ی تهیه‌ی یک چنین کوئری‌هایی را با استفاده از تعریف یک آرایه و سپس فراخوانی متد Contains بر روی آن، در اینجا مشاهده می‌کنید.



مثال 7: نتایج بازگشت داده شده را طبقه بندی کنید.

گزارشی از امکانات را تهیه کنید که در آن اگر هزینه‌ی نگهداری ماهیانه‌ی امکاناتی بیشتر از 100 دلار بود، به صورت expensive و در غیراینصورت cheap، طبقه بندی شوند.
var facilities = context.Facilities
                        .Select(x =>
                                    new
                                    {
                                        x.Name,
                                        Cost = x.MonthlyMaintenance > 100 ? "expensive" : "cheap"
                                    }).ToList();
می‌توان بر روی هر کدام از ستون‌های ذکر شده‌ی در متد Select، شرط‌هایی را نیز اعمال کرد و توانایی آن تنها به ذکر نام ستون‌ها خلاصه نمی‌شود. برای مثال در اینجا اگر MonthlyMaintenance بیشتر از مقداری بود، برچسب خاصی بجای این مقدار اصلی، نمایش داده می‌شود و چون خروجی نهایی محاسباتی آن دیگر یک ستون اصلی جدول نیست، نیاز است نام دلخواهی را برای آن انتخاب کرد که در کوئری نهایی به صورت AS Cost ظاهر می‌شود؛ البته می‌توان اینکار را در مورد ستون Name نیز انجام داد و در صورت لزوم، نام ستون دلخواه دیگری را برای آن قید کرد.



مثال 8: کار با تاریخ و زمان

لیست کاربرانی را بازگشت دهید که پس از September 2012 عضو این مجموعه شده‌اند. این گزارش باید تنها به همراه ستون‌های MemId, Surname, FirstName, JoinDate باشد.
var date = new DateTime(2012, 09, 01);
var members = context.Members.Where(x => x.JoinDate >= date)
                                            .Select(x =>
                                                        new
                                                        {
                                                            x.MemId,
                                                            x.Surname,
                                                            x.FirstName,
                                                            x.JoinDate
                                                        }).ToList();
در EF Core امکان مقایسه‌ی معمولی خواصی از نوع DateTime با وهله‌ای/مقداری از این نوع وجود دارد که در نهایت یک چنین خروجی را تولید می‌کند:



مثال 9: نتایج تکراری را از اطلاعات بازگشتی حذف کرده و آن‌ها را مرتب کنید.

گزارشی را تهیه کنید که در آن تنها فیلد Surname مرتب شده‌ی کاربران وجود دارد. از لیست Surnameها، تنها 10 مورد غیر تکراری را بازگشت دهید.
var members = context.Members.OrderBy(x => x.Surname)
                                            .Select(x =>
                                                        new
                                                        {
                                                            x.Surname
                                                        })
                                            .Distinct()
                                            .Take(10)
                                            .ToList();
با استفاده از متد OrderBy، می‌توان نتایج حاصل از کوئری را بر اساس خاصیت مشخصی مرتب کرد. سپس تعداد ستون‌های بازگشتی، توسط متد Select مشخص شده‌اند و در آخر متد Distinct سبب بازگشت موارد غیرتکراری شده (به SELECT DISTINCT ترجمه می‌شود) و متد Take، تعداد ردیف‌های بازگشت داده شده را محدود می‌کند (به SELECT  TOP 10 ترجمه می‌شود).



مثال 10: نتایج چند کوئری را با هم ترکیب کنید.

لیست نام‌های امکانات و نام‌های اشخاص را با هم ترکیب کنید.
var names = context.Members.Select(m => m.Surname).ToList()
                            .Union(context.Facilities.Select(f => f.Name).ToList()) // For now we have to use `.ToList()` here
                            .ToList();
برای ترکیب نتایج کوئری حاصل از دو جدول یا بیشتر از union استفاده می‌شود (در قالب یک کوئری):
SELECT surname
FROM members
UNION
SELECT name
FROM facilities;
 اما ... EF-Core 3x فعلا از آن به صورت تولید تنها یک کوئری SQL پشتیبانی نمی‌کند. به همین جهت در اینجا ترکیبی از LINQ to Entities و LINQ to Objects را مشاهده می‌کنید. هر جائیکه متد ToList ذکر شده، یعنی تبدیل LINQ to Entities به نتیجه‌ی حاصل یا همان materialization و از اینجا به بعد با داشتن لیستی از اشیاء درون حافظه‌ای می‌توان از LINQ to Objects استفاده کرد که استفاده‌ی از تمام امکانات زبان #C در آن میسر است.
یعنی در مثال فوق، دوبار رفت و برگشت به بانک اطلاعاتی صورت گرفته (به ازای هر ToList ذکر شده) و سپس نتیجه‌ی حاصل، در سمت کلاینت با هم Union شده‌اند و نه در سمت دیتابیس.


مثال 11: محاسبات تجمعی ابتدایی

زمان ثبت نام آخرین عضو مجموعه چیست؟

برای حل این مثال می‌توان از روش‌های مختلفی استفاده کرد:

الف) استفاده از متد تجمعی Max برای یافتن بزرگترین مقدار JoinDate
var latest = context.Members.Max(x => x.JoinDate);


متد Max برای خواص nullable می‌تواند null را بازگشت دهد و همچنین اگر این مجموعه دارای مقداری نباشد و آن خاصیت نیز nullable نباشد، استثنای Sequence contains no element را صادر می‌کند. می‌توان این استثناء را به صورت زیر با استفاده از متد DefaultIfEmpty کنترل کرد:
var latest2 = context.Members.Select(m => m.JoinDate).DefaultIfEmpty().Max();
که به صورت خاص زیر ترجمه می‌شود:
SELECT MAX([m].[JoinDate])
FROM   (SELECT NULL AS [empty]) AS [empty]
       LEFT OUTER JOIN
       [Members] AS [m]
       ON 1 = 1;
یا حتی می‌توان JoinDate را که nullable نیست، به صورت nullable معرفی کرد و سبب شد تا در صورت عدم وجود ردیفی در جدول، نال بازگشت داده شود:
var latest3 = context.Members.Max(m => (DateTime?)m.JoinDate) ?? DateTime.Now;
این روش همان کوئری «SELECT MAX([m].[JoinDate]) FROM [Members] AS [m]» را تولید می‌کند و کنترل استثنای آن در سمت کلاینت صورت می‌گیرد.

ب) بجای استفاده از متد Max می‌توان ابتدا رکوردها را بر اساس JoinDate به صورت نزولی مرتب کرد و سپس اولین عضو حاصل را بازگشت داد؛ چون اکنون بر اساس مرتب سازی صورت گرفته، در بالای لیست قرار دارد:
var latest4 = context.Members.OrderByDescending(m => m.JoinDate).Select(m => m.JoinDate).FirstOrDefault();



مثال 12: مثالی دیگر از محاسبات تجمعی ابتدایی

در مثال قبلی، نام و نام خانوادگی آخرین شخص ثبت نام شده را نیز به گزارش اضافه کنید؛ یعنی Select انجام شده شامل x.FirstName, x.Surname, x.JoinDate باشد.

یک روش انجام اینکار، همان کوئری ب مثال قبلی است که اینبار فقط Select آن فرق می‌کند:
var lastMember = context.Members.OrderByDescending(m => m.JoinDate)
                            .Select(x => new { x.FirstName, x.Surname, x.JoinDate })
                            .FirstOrDefault();


روش دیگر آن نوشتن یک sub-query در قسمت Where است:
var members = context.Members.Select(x => new { x.FirstName, x.Surname, x.JoinDate })
                                    .Where(x => x.JoinDate == context.Members.Max(x => x.JoinDate))
                                    .ToList();
می‌توان ردیفی را بازگشت داد که JoinDate آن همان بزرگترین مقدار JoinDate جدول کاربران است. یک چنین کوئری خاصی که به همراه دوبار فراخوانی context است، با فراخوانی ToList انتهایی، تنها یک کوئری را تولید می‌کند:



کدهای کامل این قسمت را در اینجا می‌توانید مشاهده کنید.