آموزش async و await
بسم الله الرحمن الرحیم
آموزش برنامه نویسی غیر همزمان - async و await
C# 5.0
هنگامی در August 15, 2012 نسخه جدید سی شارپ یعنی C# 5.0 و همچنین به همراه آن .NET 4.5 وVisual Studio 2012 ارائه شد، دو ویژگی اصلی Async Programming و Caller Information به C# 5.0 اضافه شد.
Async Feature (Asynchronous Methods)
ویژگی جدید Async در C# 5.0 دو کلمه کلیدی async و await را معرفی می کند، این دو ویژگی به شما اجازه می دهد تا کدهای غیرهمزمان (asynchronous) خود را به صورت ساده و مستقیم مانند کدهای همزمان (synchronous) که در گذشته می نوشتید، بنویسید.
در نسخه های قبل از C# 5.0، برای نوشتن برنامه های asynchronous، شما نیاز داشتید که callback ها را تعریف کنید (این کار همچنین به عنوان continuations شناخته می شود)، این کار در واقع باعث می شود که پس از اجرای دستورات غیرهمزمان شما، کنترل برنامه در اختیار پردازش تعیین شده قرار گیرد.
طبیعتا این کار باعث می شود فرایند کار شما مشکل شود و exception handling در این روش بسیار پیچیده خواهد بود.
هر دو کلمه کلیدی با یکدیگر مورد استفاده قرار می گیرند. از این رو یک عملگر await بر روی یک و یا بیش از یک expression از یک متد async عمل می کند.
یک متد async یک شی Task و یا Task<TResult> را بر می گرداند که این شی نشان دهنده کار در حال انجام بر روی یک متد است. شی Task شامل اطلاعاتی در مورد فراخوان کننده متد asynchronous است که می تواند برای نمایش وضعیت Task و ID منحصر به فرد آن و یا خروجی متد مورد استفاده قرار گیرد.
public async Task<IEnumerable<Product>> GetProductList()
{
HttpClient client = new HttpClient();
Uri address = new Uri("http://ably.ir");
client.BaseAddress = address;
HttpResponseMessage response = await client.GetAsync("myservice/product/ProductList");
if (response.IsSuccessStatusCode)
{
var list = await response.Content.ReadAsAsync<IEnumerable<Product>>();
return list;
}
else
{
return null;
}
}
Caller Information (Caller info attributes)
Caller Information می تواند در خطایابی و ساخت ابزارهای بررسی و tracing به شما کمک کند. این ویژگی به شما کمک می کند تا برنامه خود را از کدهای عمومی که در بخش های مختلف برنامه تکرار می شوند مانندlogging و tracingبی نیاز کنید.
شما می توانید اطلاعات زیر را از فراخوان کننده خود بدست آورید:
CallerFilePathAttribute
آدرس کامل فراخوان کننده که این آدرس در واقع نشان دهنده آدرسی است که پس از compile ایجاد شده است.
CallerLineNumberAttribute
شماره خطی که از آن متد فراخوانی شده است.
CallerMemberNameAttribute
نام متد و یا پراپرتی فراخوانی کننده را مشخص می کند.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
class Example
{
static void Main(string[] args)
{
Console.WriteLine("Main method Start");
InsertLog("Main");
MyMethodB();
MyMethodA();
Console.WriteLine("Main method End!");
Console.ReadLine(); // hold on result
}
static void MyMethodA()
{
InsertLog("MyMethodA");
MyMethodB();
}
static void MyMethodB()
{
// some code here.
}
static void InsertLog(string method)
{
Console.WriteLine("{0} called MyMethodB at {1}", method,
DateTime.Now);
}
}
/* Output:
Main method Start
Main called MyMethodB at 11/17/2013 11:12:24 PM
MyMethodA called MyMethodB at 11/17/2013 11:12:24 PM
Main method End!
*/
در متدهای Main و MyMethodA از متد InsertLog برای logging استفاده کرده ایم، حال کد خود را به صورت زیر تغییر می دهیم.
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
class Example
{
static void Main(string[] args)
{
Console.WriteLine("Main method Start");
MyMethodB();
MyMethodA();
Console.WriteLine("Main method End!");
Console.ReadLine();
}
static void MyMethodA()
{
MyMethodB();
}
static void MyMethodB([CallerMemberName] string memberName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
{
InsertLog(memberName);
}
static void InsertLog(string method)
{
Console.WriteLine("{0} called MyMethodB at {1}", method, DateTime.Now);
}
}
/*Output:
Main method Start
Main called MyMethodB at 11/17/2013 10:30:11 PM
MyMethodA called MyMethodB at 11/17/2013 10:30:11 PM
Main method End!
*/