پروژه‌ها
PdfReport
کتابخانه PdfReport جهت ایجاد گزارشات متنوعی با خروجی PDF کاملا سازگار با زبان فارسی تهیه شده است. استفاده از آن صرفا با کدنویسی (Code first) میسر بوده و بازه وسیعی از فناوری‌های مختلف مبتنی بر دات نت را پوشش می‌دهد؛ مانند WinForms، WPF، برنامه‌های وب و غیره و کلا هرجایی که دات نت فریم ورک 3.5 به بعد به صورت کامل در دسترس باشد.
به کمک کتابخانه PdfReport دسترسی گسترده‌ای به منابع داده‌ای مختلف خواهید یافت. منابعی که لزوما بانک اطلاعاتی نیستند؛ مانند یک لیست جنریک و یا حتی یک anonymously typed list حاصل از یک کوئری LINQ.
این کتابخانه علاوه بر تبدیل اطلاعات شما به گزارشات مبتنی بر PDF، امکان تهیه خروجی خودکار اکسل (2007 به بعد) را نیز دارد. فایل خروجی آن، به صورت پیوست درون فایل PDF تهیه شده قرار می‌گیرد و جزئی از آن می‌شود.
مسایل امنیتی مانند رمزنگاری فایل PDF حاصل و یا حتی افزودن امضای دیجیتال به فایل نهایی تولیدی نیز در آن لحاظ شده است.
کتابخانه PdfReport بر پایه کتابخانه‌های معروف سورس باز iTextSharp و EPPlus تهیه شده است. حداقل مزیت استفاده از آن، صرفه جویی در وقت شما جهت آموختن ریزه کاری‌های مرتبط با هر کدام از کتابخانه‌های یاده شده است. برای نمونه جهت فراگیری کار با iTextSharp نیاز است یک کتاب 600 صفحه‌ای به نام iText in action را مطالعه و تمرین کنید. این مورد منهای مسایل و نکات متعدد مرتبط با زبان فارسی است که در این کتاب به آن‌ها اشاره‌ای نشده است.

مطالب
مونیتور کردن وضعیت یک سایت در دات نت

فرض کنید می‌خواهیم وضعیت یک سایت را از لحاظ قابلیت دسترسی مونیتور کنیم، آیا Up است، Down است و امثال آن. یک سری از وب سرورها ping را بسته‌اند (ICMP Replies). بنابراین الزاما با استفاده از این روش ساده نمی‌توان به مقصود رسید.
خوشبختانه انجام این‌کار با استفاده از فضای نام استاندارد System.Net و کلاس HttpWebRequest ، بدون نیاز به هیچگونه کلاس یا کامپوننت خارجی، به سادگی قابل انجام است. کلاس زیر به همین منظور تهیه شده است:

using System;
using System.Net;

public class CSiteMonitor
{
public struct UrlHeaderInfo
{
public DateTime _lastModified;
public string _statusCode;
public string _errorMessage;
}

/// <summary>
/// آیا آدرس اینترنتی وارد شده معتبر است؟
/// </summary>
/// <param name="url">آدرس مورد نظر جهت بررسی</param>
/// <returns></returns>
public static bool IsValidURL(string url)
{
try
{
Uri uri = new Uri(url);
return (uri.Scheme == Uri.UriSchemeHttp) || (uri.Scheme == Uri.UriSchemeHttps);
}
catch { return false; }
}
/// <summary>
/// آدرس اینترنتی جهت بررسی
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
/// <exception cref="ArgumentException">آدرس اینترنتی وارد شده معتبر نیست</exception>
public static UrlHeaderInfo GetSiteHeaderInfo(string url)
{
if (!IsValidURL(url))
throw new ArgumentException("آدرس اینترنتی وارد شده معتبر نیست", "url");

UrlHeaderInfo hhi = new UrlHeaderInfo { _lastModified = DateTime.Now, _statusCode = "NOK!", _errorMessage = string.Empty };

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
//request.Proxy
request.Method = "HEAD";
request.AllowAutoRedirect = true;
request.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.0; ; rv:1.8.0.7) Gecko/20060917 Firefox/1.9.0.1";
request.Timeout = 1000 * 300;
request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;

try
{
using (HttpWebResponse response = (HttpWebResponse) request.GetResponse())
{
hhi._statusCode = response.StatusCode.ToString();
hhi._lastModified = response.LastModified;
}
}
catch (Exception ex)
{
hhi._errorMessage = ex.Message;
}

return hhi;
}
}

توضیحات:
- در متد GetSiteHeaderInfo نیاز بود تا از یک تابع بیش از یک خروجی داشته باشیم. راه‌های زیاد برای انجام این‌کار هست.برای مثال:
الف)ارائه خروجی‌ها به صورت یک آرایه. زیاد جالب نیست، چون اگر شخصی دقیقا مستندات متد شما را مطالعه نکند نمی‌داند که ترتیب خروجی‌ها چگونه است و هر کدام چه معنایی دارند.
ب)ارائه خروجی‌ها با استفاده از آرگومان‌هایی از نوع out یا ref . در دنیای شیء گرایی این نوع روش‌ها را باید منسوخ شده در نظر گرفت و صرف سازگاری با زبان‌هایی مانند C که این روش در آن‌ها رواج دارد (استفاده از آرگومان‌هایی از نوع اشاره‌گر) باید به آن نگاه کرد و نه بیشتر.
ج)خروجی‌ها را به صورت یک کلاس یا struct درنظر گرفت تا استفاده کننده دقیقا بداند که فیلد خروجی چه معنایی دارد و هم چنین دقیقا چه تعداد خروجی مد نظر است.

- حتما باید از try/finally جهت اطمینان حاصل نمودن از بسته شدن response استفاده شود، در غیر اینصورت پس از دو خطای متوالی حاصل شده عملا دیگر نمی‌توان از شیء response استفاده کرد. البته همانطور که پیش تر نیز ذکر شد، عبارت using توسط کامپایلر به try/finally بست داده می‌شود، بنابراین جهت خوانایی بیشتر کد بهتر است از این روش استفاده شود.
- جهت بلاک نشدن درخواست بهتر است از یک UserAgent کمک گرفته شود.
- جهت بررسی اعتبار یک آدرس اینترنتی یا می‌توان از Regular expressions استفاده کرد یا از شیء Uri که روش آن‌را ملاحظه می‌کنید.
- اگر در شبکه داخلی خود از پروکسی استفاده می‌شود، می‌توان قسمت request.Proxy را با شیء پروکسی تنظیم شده مطابق مشخصات پروکسی سرور خود، بکار برد.
- در این مثال بیشتر هدف پیاده سازی کلاس دریافت اطلاعات هدر سایت بود و از ارائه کدهای مربوط به تایمر یا یک ترد جهت بررسی متوالی وضعیت سایت صرفنظر شد.

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

CSiteMonitor.UrlHeaderInfo info = CSiteMonitor.GetSiteHeaderInfo("http://www.google.com");
MessageBox.Show(info._statusCode);

مطالب
چگونه تشخیص دهیم اسمبلی دات نت ما وصله شده است؟

یکی از روش‌هایی که برای بررسی یکپارچگی فایل‌ها مورد استفاده قرار می‌گیرد و عموما در دنیای سخت افزار و firmware های نوشته شده برای آن‌ها مرسوم است، قرار دادن CRC32 فایل در قسمتی از فایل و بررسی آن حین Boot سیستم است. اگر CRC32 جدید با CRC32 اصلی یکسان نباشد به این معنا است که فایل در حال اجرا پیش تر دستکاری شده است.
اما در دات نت فریم ورک روش متداول اینکار چیست؟ برای این منظور اضافه کردن امضای دیجیتال به فایل و اسمبلی نهایی تولیدی (فایل exe یا dll تولیدی) توصیه می‌شود (مراجعه به قسمت خواص پروژه و افزودن امضای دیجیتال جدید فقط با چند کلیک، +).
این مورد خوب است (با توجه به اینکه از الگوریتم‌های RSA و SHA1 استفاده می‌کند)، لازم است، اما کافی نیست زیرا ابزارهای حذف آن وجود دارند. به عبارتی برای وصله کردن این فایل‌ها فقط کافی است این امضای دیجیتال حذف شود و زمانی هم که نباشد، بررسی خاصی در مورد یکپارچگی فایل صورت نخواهد گرفت.
اما اگر باز هم نگران patch یا وصله شدن اسمبلی دات نت خود هستید این مورد افزودن امضای دیجیتال را حتما انجام دهید. مهم‌ترین خاصیت آن این است که یک سری تابع native در دات نت فریم ورک برای بررسی نبود آن وجود دارند (+):
[DllImport("mscoree.dll", CharSet=CharSet.Unicode)]
public static extern bool StrongNameSignatureVerificationEx(string wszFilePath, bool fForceVerification, ref bool pfWasVerified);

wszFilePath مسیر فایلی است که باید بررسی شود.
fForceVerification آیا متغیر pfWasVerified نیز مقدار دهی گردد؟
خروجی تابع مشخص می‌سازد که آیا strong name موجود و معتبر است یا خیر؟

و مثالی از استفاده‌ی آن (که بهتر است در یک تایمر نیم ساعت پس از اجرای برنامه رخ دهد):
using System;
using System.Reflection;
using System.Runtime.InteropServices;

namespace SigCheck
{
public class Validation
{
[DllImport("mscoree.dll", CharSet = CharSet.Unicode)]
public static extern bool StrongNameSignatureVerificationEx(
string wszFilePath, bool fForceVerification, ref bool pfWasVerified);

public static void SigCheck()
{
var assembly = Assembly.GetExecutingAssembly();
bool pfWasVerified = false;
if (!StrongNameSignatureVerificationEx(assembly.Location, true, ref pfWasVerified))
{
//خاتمه برنامه در صورت عدم وجود امضای دیجیتال معتبر
throw new Exception();
}
}
}

class Program
{
static void Main(string[] args)
{
Validation.SigCheck();
}
}
}
خوب، شاید پس از حذف و وصله شدن اسمبلی، مجددا strong name به آن اضافه شود! ، آن وقت چه باید کرد؟
زمانیکه به اسمبلی خود امضای دیجیتال اضافه می‌کنید، هش رمزنگاری شده فایل با الگوریتم RSA ، به همراه public key مورد نیاز در اسمبلی ذخیره می‌شوند. از آنجائیکه private key الگوریتم RSA را منتشر نکرده‌اید، شکستن الگوریتم RSA کار ساده‌ای نیست، مگر اینکه جفت کلید خودشان را تولید کنند و public key جدید را در فایل نهایی قرار دهند. بدیهی است این public key جدید با کلید عمومی ما که متناظر است با کلید خصوصی منتشر نشده‌ی اصلی، تطابق نخواهد داشد. برای آشنایی با تابعی که این بررسی را انجام می‌دهد به مقاله ذکر شده رجوع کنید:



مطالب
آشنایی با انواع Control ID ها در ASP.Net

اگر مطلب تبدیل پلاگین‌های جی‌کوئری به کنترل‌های ASP.Net را مطالعه کرده باشید، در مورد ClientID بحث شد. با مراجعه به اصول HTML‌ درخواهیم یافت که هر کنترل یا شیء مربوطه می‌تواند شامل ID و name باشد. عموما در کدهای جاوا اسکریپتی برای دسترسی به یک شیء در صفحه از ID آن شیء به صورت document.getElementById استفاده شده و از name برای پردازش‌های سمت سرور استفاده می‌شود. برای مثال اگر به دوران ASP کلاسیک برگردیم، از شیء Request برای دریافت مقادیر ارسال شده به سرور با استفاده از name شیء مورد نظر استفاده می‌شد/می‌شود.
در حالت فرم‌های معمولی ، ID و name عموما یکسان هستند. اما اگر از master page ها استفاده شود یا از یک user control برای ترکیب چندین کنترل کمک گرفته شود، دیگر ID و name در فرم رندر شده نهایی ASP.Net یکسان نخواهند بود. برای مثال:
<input name="ctl00$ContentPlaceHolder1$txtID" type="text" id="ctl00_ContentPlaceHolder1_txtID" />

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

public virtual string ClientID
{
get
{
this.EnsureID();
string uniqueID = this.UniqueID;
if ((uniqueID != null) && (uniqueID.IndexOf(this.IdSeparator) >= 0))
{
return uniqueID.Replace(this.IdSeparator, '_');
}
return uniqueID;
}

}

و جهت تولید name به صورت زیر عمل می‌شود (یک الگوریتم بازگشتی است):
<Container>$<Container>$<Container>$<Container>$...$<ID>

زمانیکه یک کنترل توسط ASP.Net رندر می‌شود، خاصیت UniqueID معادل name آن و ClientID معادل ID آن کنترل در سمت کلاینت خواهد بود. اگر از IE استفاده کنید به هر نحوی سعی در پردازش اسکریپت شما خواهد کرد و document.getElementById بالاخره جواب خواهد داد. اما اگر از سایر مرورگرها استفاده کنید، در صورتیکه بجای ID از name استفاده شده باشد، اسکریپت شما با پیغامی مبنی بر یافت نشدن شیء مورد نظر متوقف خواهد شد (چون مقدار این‌دو همانطور که ملاحظه کردید الزاما یکسان نخواهد بود).
این نکته در طراحی کنترل‌های ASP.Net که از کدهای جاوا اسکریپتی استفاده می‌کنند بسیار مهم است. در تست اول و با یک صفحه ساده کنترل شما خوب کار خواهد کرد. اما اگر همین کنترل را بر روی یک صفحه مشتق شده از یک master page قرار دهید، دیگر ID آن یافت نشده و کدهای جاوا اسکریپتی شما کار نخواهند کرد. به همین جهت اگر قرار است قسمت جاوا اسکریپتی کنترل شما توسط کنترل به صورت خودکار ایجاد شود و در این کد ارجاعی به شیء جاری وجود دارد، این شیء جاری با استفاده از ClientID آن در سمت کلاینت قابل دسترسی خواهد بود و نه با استفاده از ID سمت سرور و یا UniqueID آن.

مطالب دوره‌ها
آشنایی با AOP IL Weaving
IL Weaving در AOP به معنای اتصال Aspects تعریف شده، پس از کامپایل برنامه به فایل‌های باینری نهایی است. اینکار با ویرایش اسمبلی‌ها در سطح IL یا کد میانی صورت می‌گیرد. بنابراین در این حالت دیگر یک محصور کننده و پروکسی، در این بین جهت مزین سازی اشیاء، در زمان اجرای برنامه تشکیل نمی‌شود. بلکه فراخوانی Aspects به معنای فراخوانی واقعی قطعه کدهایی است که به اسمبلی‌های برنامه پس از کامپایل آن‌ها تزریق شده‌اند.
در دنیای دات نت، ابزارهای چندی امکان انجام IL Weaving را فراهم ساخته‌اند که تعدادی از آن‌ها به قرار ذیل هستند:
- PostSharp
- LOOM.NET
- Wicca
و ...

در بین این‌ها، PostSharp معروفترین فریم ورک AOP بوده و در ادامه از آن استفاده خواهیم کرد.


پیشنیاز ادامه بحث

ابتدا یک پروژه کنسول جدید را آغاز کرده و سپس در خط فرمان پاور شل نوگت در VS.NET دستور ذیل را اجرا کنید:
 PM> Install-Package PostSharp
به این ترتیب ارجاعی به PostSharp به پروژه جاری اضافه خواهد شد. البته حجم آن نسبتا بالا است؛ نزدیک به 20 مگ به همراه ابزارهای تزریق کد همراه با آن. مجوز استفاده از آن نیز تجاری و مدت دار است.


مراحل ایجاد یک Aspect برای پروسه IL Code Weaving

ابتدا یک کلاس پایه مشتق شده از کلاسی ویژه موجود در یکی از فریم ورک‌های AOP باید تعریف شود. مرحله بعد، کار اتصال این Aspect می‌باشد که توسط پردازشگر ثانویه IL Code Weaving انجام می‌شود.
در ادامه قصد داریم همان مثال LoggingInterceptor قسمت دوم این سری را با استفاده از IL Code Weaving پیاده سازی کنیم.
using System;

namespace AOP03
{
    public class MyType
    {
        public void DoSomething(string data, int i)
        {
            Console.WriteLine("DoSomething({0}, {1});", data, i);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            new MyType().DoSomething("Test", 1);
        }
    }
}
کدهای برنامه همانند قبل است. اما اینبار بجای استفاده از Interceptors، با ارث بری از کلاس OnMethodBoundaryAspect کتابخانه PostSharp شروع خواهیم کرد:
using System;
using PostSharp.Aspects;

namespace AOP03
{
    [Serializable]
    public class LoggingAspect : OnMethodBoundaryAspect
    {
        public override void OnEntry(MethodExecutionArgs args)
        {
            Console.WriteLine("On Entry");
        }

        public override void OnExit(MethodExecutionArgs args)
        {
            Console.WriteLine("On Exit");
        }

        public override void OnSuccess(MethodExecutionArgs args)
        {
            Console.WriteLine("On Success");
        }

        public override void OnException(MethodExecutionArgs args)
        {
            Console.WriteLine("On Exception");
        }
    }
}
نیاز است این کلاس توسط ویژگی Serializable مزین شود تا توسط PostSharp قابل استفاده گردد. همانطور که ملاحظه می‌کنید، مراحل مختلف اجرای یک Aspcet در اینجا با override متدهای کلاس پایه OnMethodBoundaryAspect پیاده سازی شده‌اند. این مراحل را پیشتر در زمان استفاده از Interceptors توسط try/finally/catch بررسی کرده بودیم.
اکنون اگر برنامه را اجرا کنیم، اتفاق خاصی رخ نداده و همان خروجی معمول متد DoSomething در کنسول نمایش داده خواهد شد. بنابراین در مرحله بعد نیاز است تا این Aspect را به کدهای برنامه متصل کنیم.
کلاس OnMethodBoundaryAspect در کتابخانه PostSharp، از کلاس MulticastAttribute مشتق می‌شود. بنابراین LoggingAspect ایی را که ایجاد کرده‌ایم نیز می‌توان به صورت یک ویژگی به متد‌های مورد نظر خود افزود:
    public class MyType
    {
        [LoggingAspect]
        public void DoSomething(string data, int i)
        {
            Console.WriteLine("DoSomething({0}, {1});", data, i);
        }
    }
اکنون اگر برنامه را اجرا کنیم، با خروجی زیر مواجه خواهیم شد:
 On Entry
DoSomething(Test, 1);
On Success
On Exit
برای اینکه بتوان عملیات رخ داده را بهتر توضیح داد می‌تواند از یک دی‌کامپایلر مانند برنامه معروف Reflector استفاده کرد:
public void DoSomething(string data, int i)
{
    <>z__Aspects.a0.OnEntry(null);
    try
    {
        Console.WriteLine("DoSomething({0}, {1});", data, i);
        <>z__Aspects.a0.OnSuccess(null);
    }
    catch (Exception)
    {
        <>z__Aspects.a0.OnException(null);
        throw;
    }
    finally
    {
        <>z__Aspects.a0.OnExit(null);
    }
}
این کدی است که به صورت پویا توسط PostSharp به اسمبلی نهایی فایل اجرایی برنامه تزریق شده است.

خوب! این یک روش اتصال Aspects به برنامه است. اما اگر همانند Interceptors بخواهیم Aspect تعریف شده را سراسری اعمال کنیم چکار باید کرد (بدون نیاز به قرار دادن ویژگی بر روی تک تک متدها)؟
برای اینکار ابتدا نیاز است میدان عملکرد Aspect تعریف شده را توسط ویژگی MulticastAttributeUsage محدود کنیم تا برای مثال به خواص اعمال نشوند:
 [Serializable]
[MulticastAttributeUsage(MulticastTargets.Method, TargetMemberAttributes = MulticastAttributes.Instance)]
public class LoggingAspect : OnMethodBoundaryAspect
سپس فایل AssemblyInfo.cs استاندارد پروژه را گشوده و سطر زیر را به آن اضافه کنید:
 [assembly: LoggingAspect(AttributeTargetTypes = "AOP03.*")]
توسط AttributeTargetTypes می‌توان اعمال این Aspect را به یک فضای نام خاص نیز محدود کرد.

مزیت روش IL Code Weaving نسبت به Interceptors، کارآیی و سرعت بالاتر است. از این جهت که کدهایی که قرار است اجرا شوند، پیشتر در اسمبلی برنامه قرار گرفته‌اند و نیازی نیست تا در زمان اجرا، کدی به برنامه به صورت پویا تزریق گردد.
بازخوردهای دوره
ارتباطات بلادرنگ و SignalR
در اینجا
- در سمت کلاینت فایروال مانعی نخواهد بود چون ارتباطات از طریق مرورگر (هم می‌تواند) انجام می‌شود.
- باز هم نهایتا از سوکت‌ها استفاده خواهد شد اما در سطحی بالاتر و بدون درگیری با جزئیات آن‌ها. اینبار یک فریم ورک آماده، تست شده و تهیه شده برفراز سوکت‌های دات نت و ویندوز در اختیار شما است. به علاوه این فریم ورک فراتر است از صرفا برقراری ارتباط و ارسال داده، بلکه حالت امکان اجرای متدهای خاصی در سمت کلاینت یا سرور را هم دارا است (بحث قسمت بعد).
- تنوع کلاینت‌ها. محدود به یک برنامه ویندوزی نخواهید بود. مثلا امکان استفاده از یک کلاینت jQuery، که برای اجرا، نیازی به سطح دسترسی خاصی ندارد، یا حتی یک کلاینت سیلورلایت یا اندروید و غیره هم برای آن تهیه کرده‌اند.
- امکان استفاده از IIS به عنوان سرور. همین مساله یعنی درگیر نشدن با مسایلی مانند مقیاس پذیری، مدیریت تعداد کانکشن‌های بالا و امثال آن.
- امکان یکپارچه کردن یک برنامه سرویس دهنده هاب با یک برنامه ASP.NET در کنار هم در یک پروژه.
و ...
مطالب
امکان تعریف حلقه‌ی foreach بر روی هر نوع مجموعه‌ای از داده‌ها در C# 9.0
عبارت foreach در زبان #C، امکان پیمایش اعضای یک مجموعه را میسر می‌کند؛ اما نه هر مجموعه‌ای. این مجموعه‌ی خاص باید به این صورت تعریف شده باشد:
الف) <IEnumerable<T را پیاده سازی کرده باشد.
ب) و یا ... مهم نیست که این مجموعه حتما <IEnumerable<T را پیاده سازی کرده باشد. اگر این مجموعه به همراه یک متد عمومی خاص با نام GetEnumerator باشد که خروجی آن دارای خاصیت عمومی T Current است (یکی از اعضای اینترفیس <IEnumerable<T) و همچنین به همراه متد عمومی bool MoveNext نیز هست (یکی از اعضای اینترفیس IEnumerator)، قابلیت کار با حلقه‌ی foreach را پیدا می‌کند و ... اکنون در C# 9.0 می‌توان متد GetEnumerator را به صورت یک متد الحاقی، به هر نوع دلخواهی اعمال کرد! یعنی می‌توان برای هر نوعی در صورت نیاز، یک GetEnumerator خاص را طراحی کرد که سبب به کار افتادن حلقه‌ی foreach بر روی آن شود.


مثال 1: نوع <IEnumerator<T با حلقه‌ی foreach سازگار نیست

نوع <IEnumerator<T به دلیل نداشتن متد عمومی GetEnumerator که ذکر شد:
    public interface IEnumerator<out T> : IEnumerator, IDisposable
    {
        //
        // Summary:
        //     Gets the element in the collection at the current position of the enumerator.
        //
        // Returns:
        //     The element in the collection at the current position of the enumerator.
        T Current { get; }
    }
قابلیت پیمایش توسط حلقه‌ی foreach را ندارد. اگر در C# 8.0 این حلقه را بر روی آن اعمال کنیم، به خطای کامپایلر زیر می‌رسیم:
Error CS1579 foreach statement cannot operate on variables of type ‘IEnumerator’
because ‘IEnumerator’ does not contain a public instance or extension definition for ‘GetEnumerator’
 اما می‌توان به صورت زیر در C# 9.0، این متد را به آن اضافه کرد:
static class Extensions
{
   public static IEnumerator<T> GetEnumerator<T>(this IEnumerator<T> enumerator) => enumerator;
}

اکنون حلقه‌ی foreach را می‌توان بر روی نوع‌های <IEnumerator<T نیز بکار گرفت:
class Program
{
    void Main()
    {
        var enumerator = Enumerable.Range(0, 10).GetEnumerator();
        foreach (var item in enumerator)
        {
            Console.WriteLine(item);
        }
    }
}

این نکته بر روی نمونه‌ی async آن نیز قابل اعمال است که مثالی از آن‌را در ادامه مشاهده می‌کنید:
static class Extensions
{
    public static IAsyncEnumerator<T> GetAsyncEnumerator<T>(this IAsyncEnumerator<T> enumerator) => enumerator;
}

class Program
{
    static async Task Main()
    {
        var enumerator = GetAsyncEnumerator();
        await foreach (var item in enumerator)
        {
            Console.WriteLine(item);
        }
    }

    static async IAsyncEnumerator<int> GetAsyncEnumerator()
    {
        yield return 0;
        await Task.Delay(1);
        yield return 1;
    }
}


مثال 2: اضافه کردن پشتیبانی از حلقه‌ی foreach بر روی نوع‌های tuple

مثال زیر را درنظر بگیرید:
class Program
{
    static void Main()
    {
        foreach (var item in (1, 2, 3))
        {
            Console.WriteLine(item);
        }
    }
}
در اینجا سعی کرده‌ایم تا حلقه‌ی foreach را بر روی یک tuple سه عضوی، اعمال کنیم. اما با خطای کامپایلر زیر مواجه می‌شویم:
foreach statement cannot operate on variables of type '(int, int, int)'
because '(int, int, int)' does not contain a public instance or extension definition
for 'GetEnumerator' [CS9Features]csharp(CS1579)
برای رفع این خطا در C# 9.0 تنها کافی است متد الحاقی GetEnumerator مخصوص نوع آن‌را طراحی و به برنامه اضافه کرد:
static class Extensions
{
    public static IEnumerator<object> GetEnumerator<T1, T2, T3>(this ValueTuple<T1, T2, T3> tuple)
    {
        yield return tuple.Item1;
        yield return tuple.Item2;
    }
}
مطالب
لینک‌های هفته‌ی آخر دی

وبلاگ‌ها ، سایت‌ها و مقالات ایرانی (داخل و خارج از ایران)


Visual Studio


ASP. Net



طراحی و توسعه وب



PHP


اس‌کیوال سرور


سی شارپ


عمومی دات نت


ویندوز


مسایل اجتماعی و انسانی برنامه نویسی


متفرقه


بازخوردهای دوره
آشنایی با مدل برنامه نویسی TAP
با سلام 
من دستور زیر را در پاورشل نیوگت اجرا کردم اما از متدها الحاقی نمی‌تونم استفاده کنم در دات نت 4
PM> Install-Package Microsoft.Bcl.Async 
با تشکر
مطالب
نگاشت JSON به کلاس‌های معادل آن

یکی از مواردی که عموما در برنامه نویسی با آن سر و کار داریم، parse اطلاعات با فرمت‌های مختلف است. از CSV تا XML تا ... JSON .
در مورد کار با XML در دات نت فریم ورک، فضاهای نام مرتبط زیادی وجود دارند؛ برای مثال System.Xml.Linq و System.Xml . همچنین یک روش دیگر هم برای کار با اطلاعات XML ایی در دات نت وجود دارد. می‌شود کلاس معادل یک فایل XML را تولید و سپس اطلاعات آن‌را به این کلاس نگاشت کرد. اطلاعات بیشتر : (^). این برنامه کار خود مایکروسافت است.
در مورد JSON از دات نت سه و نیم به بعد کارهایی صورت گرفته مانند : (^). اما آنچنان دلچسب نیست. جهت رفع این خلاء کتابخانه‌ی سورس باز و بسیار کاملی در این زمینه به نام JSON.NET تهیه شده که از این آدرس قابل دریافت است: (^)
و خبر خوب اینکه امکان تهیه کلاس‌های معادل اطلاعات JSON ایی هم مدتی‌است توسط برنامه نویس‌های مستقل تهیه شده است. یا می‌توان از امکانات توکار دات نت استفاده کرد یا از کتابخانه‌‌هایی مانند JSON.NET یا از هیچکدام! می‌توان یک راست کل اطلاعات JSON ایی دریافتی را به یک یا چند کلاس معادل آن نگاشت کرد:
  • و یا یک ابزار آنلاین مشابه: json2csharp