نظرات مطالب
Microbenchmark
مطلب جالبی هست از یکی از اعضای تیم کامپایلر سی شارپ :(^)
بحث محاسبه کارآیی در دات نت شامل زمان صرف شده برای JIT اولیه کدها هم هست. به همین جهت اجرای اولیه اندکی بیشتر زمان می‌بره. همچنین GC هم در اینجا در ترد دیگری به موازات کار شما مشغول به کار است و اگر در یک اجرا زمان خوبی بدست آوردید به این معنا نیست که الزاما در اجرای بعدی هم همان زمان را بدست می‌آورید چون GC موکول شده به بعد. ضمن اینکه این نوع محاسبات چون به صورت ایزوله انجام می‌شود عموما بیانگر شرایط دنیای واقعی که پارامترهای زیادی در آن‌ها دخیل هستند، نیست.
و ... اینکه برای خیلی از برنامه نویس‌ها این نوع مقایسه‌ها بیشتر جذاب هستند:
Head-to-head benchmark: C++ vs .NET

مطالب
انجمن سایت LLBLGEN سورس باز شد

LLBLGEN یکی از ORM های تجاری بسیار با کیفیت دات نت است و علاوه بر اینکه هویت مستقلی دارد، امکان تولید کدهای مخصوص Entity framework و NHibernate را هم دارا است.
اخیرا این شرکت تصمیم گرفته است که سیستم پشتیبانی مشتریان خودش را که نمونه‌ای از آن‌را در اینجا می‌توانید ملاحظه کنید، سورس باز کند.
حداقل پیشنیازهای نصب این انجمن به شرح زیر است:
- ASP.NET 2.0+
- SQL Server 2000 or higher / CE Desktop 3.5
- NET 3.5+
لطفا جهت دریافت آن به این آدرس و جهت ملاحظه‌ی قابلیت‌های آن به این آدرس مراجعه نمائید.

مطالب
خواندن فید گزارش آب و هوای یاهو با استفاده از روش Xml serialization

در مطلب قبلی (در مورد کتابخانه anti-xss مایکروسافت) از روش xml serialization برای خواندن فایل xml حملات استفاده کردیم.
ایجاد این کلاس و نگاشت اشیاء با توجه به ساختار ساده آن به صورت دستی و به‌سادگی انجام شد. اکنون به مثال زیر دقت بفرمائید:
سرویس آب و هوای یاهو برای شهرهای مختلف ایران از طریق لینک زیر قابل استفاده است:
http://weather.yahoo.com/regional/IRXX.html
اگر به صفحات شهرهای مختلف مراجعه نمائید، یک فید rss هم مشاهده خواهید کرد، برای مثال در مورد تهران داریم:
http://weather.yahooapis.com/forecastrss?p=IRXX0018&u=c
ساختار این فایل xml تا حدودی با یک rss استاندارد تطابق دارد. اما اگر به سورس xml آن دقت کنیم تگ‌های دیگری را نیز مشاهده خواهیم کرد که برای مثال دما ، تاریخ و شرایط جوی را به صورت دقیقی و با استفاده از اصول xml ارائه می‌دهند.

<yweather:condition text="Partly Cloudy" code="29" temp="10" date="Tue, 11 Nov 2008 5:30 pm IRT" />

خوب، برای دریافت این اطلاعات چه باید کرد؟ یکی از روش‌های متداول برای کار با این نوع داده‌ها، استفاده از کلاس DataSet در دات نت و فراخوانی متد ReadXml آن است (یک آدرس اینترنتی را هم می‌تواند دریافت کند). سپس مطابق روش‌های معمول ADO.Net می‌توان به تگ‌ها ومقادیر آنها دسترسی داشت.
روش‌ بالا هر چند مشکلی ندارد اما به زیبایی کار با خواص یک کلاس متناظر با آن فایل xml نیست. اما در اینجا برای استفاده از روش xml serialization یک مشکل وجود دارد! ایجاد دستی این کلاس که بیانگر عملکرد آن فایل xml است کار ساده‌ای نیست.
خوشبختانه به همراه SDK‌ دات نت فریم ورک 2، برنامه‌ای به نام xsd.exe نیز همراه است که کار ایجاد یک کلاس cs یا vb را از یک فایل xml جهت این منظور انجام می‌دهد (این برنامه برای مثال در مسیر C:\Program Files\Microsoft.NET\SDK\v2.0\Bin قرار دارد).

برای ایجاد فایل کلاس به صورت خودکار از روی یک فایل xml موجود باید به ترتیب زیر عمل کرد:
الف) ایجاد فایل xsd متناظر (XML Schema Definition)
برای اینکار در خط فرمان تایپ کنید:
xsd.exe file.xml

نکته 1:
روش دیگر انجام این کار : فایل xml را در VS.net باز کنید، از منوی بالای صفحه گزینه xml را انتخاب نموده و بر روی دکمه Create Schema کلیک کنید.

ب) ایجاد فایل cs یا vb از روی فایل(های) xsd ایجاد شده
در اینجا برای فید آب و هوای یاهو سه فایل xsd تولید خواهد شد. برای تبدیل آنها به کلاس cs باید دستور زیر را در خط فرمان اجرا کرد:

Xsd.exe file_1.xsd file_2.xsd file_3.xsd /c

این مورد نکته مهمی است و تنها اگر یکی از فایل‌ها اینجا ذکر شوند، کلاس ناقصی تشکیل خواهد شد. (برای نمونه فایل xssAttacks.xml مطلب قبلی، ساختار ساده‌ای داشته و تنها به یک فایل xsd ختم خواهد شد)

نکته 2:
برای انتخاب زبان VB (با توجه به این‌که پیش فرض آن CS است) می‌توان به صورت زیر عمل کرد:
xsd.exe file.xsd /c  /l:vb

نکته 3:
برای تولید فایل xsd ، از برنامه Infer.exe نیز می‌توان استفاده کرد (خروجی نهایی دقیق‌تری را ارائه می‌دهد). این برنامه را از اینجا دریافت کنید.

تصاویر زیر مقایسه دو فایل کلاس نهایی تولید شده از xsd های این دو برنامه است:






پس از طی این مراحل فایل کلاس ما برای xml serialization آماده خواهد شد. مرحله بعد دریافت اطلاعات و نگاشت آن به این کلاس تولید شده است:

public static rss DeserializeFromXML()
{
XmlSerializer deserializer =
new XmlSerializer(typeof(rss));
using (XmlReader reader = XmlReader.Create("http://weather.yahooapis.com/forecastrss?p=IRXX0018&u=c"))
{
return (rss)deserializer.Deserialize(reader);
}
}

کلاس rss از فید xml و فایل‌های xsd آن که تولید کردیم به صورت خودکار ایجاد شده است.
اکنون برای مثال خواندن وضعیت فعلی جوی از فید دریافتی به سادگی زیر است:

rss data = DeserializeFromXML();
MessageBox.Show(data.channel.item.condition.text);


مطالب
فراخوانی سرویس های WCF به صورت Async
هنگام تولید و توسعه سیستم‌های مبتنی بر WCF حتما نیاز به سرویس هایی داریم که متد‌ها را به صورت Async اجرا کنند. در دات نت 4.5 از Async&Await استفاده می‌کنیم(^). ولی در پروژه هایی که تحت دات نت 4 هستند این امکان وجود ندارد(البته می‌تونید Async&Await CTP رو برای دات نت 4 هم نصب کنید(^ )). فرض کنید پروژه ای داریم تحت دات نت 3.5 یا 4 و قصد داریم یکی از متد‌های سرویس WCF آن را به صورت Async پیاده سازی کنیم. ساده‌ترین روش این است که هنگام Add Service Reference از پنجره Advanced  به صورت زیر عمل کنیم:


مهم‌ترین عیب این روش این است که در این حالت تمام متد‌های این سرویس رو هم به صورت Sync و هم به صورت Async تولید می‌کنه در حالی که ما فقط نیاز به یک متد Async داریم.

 در این پست قصد دارم پیاده سازی این متد رو بدون استفاده از Async&Await و Code Generation توکار دات نت شرح بدم که با دات نت 3.5 هم سازگار است.

ابتدا یک پروژه از نوع WCF Service Application ایجاد کنید.
یک ClassLibrary جدید به نام Model بسازید و کلاس زیر را به عنوان مدل در آن قرار دهید.(این اسمبلی باید هم به پروژه‌های کلاینت و هم به پروژه‌های سرور رفرنس داده شود)
    [DataContract]
    public class Book
    {
        [DataMember]
        public int Code { get; set; }

        [DataMember]
        public string Title { get; set; }

        [DataMember]
        public string Author { get; set; }
    }
حال  پیاده سازی سرویس و Contract مربوطه را شروع می‌کنیم.
#Class Library به نام Contract بسازید. قصد داریم از این لایه به عنوان قرارداد‌های سمت کلاینت و سرور استفاده کنیم. اینترفیس زیر را به عنوان BookContract در آن بسازید.
   [ServiceContract]
    public interface IBookService
    {
        [OperationContract( AsyncPattern = true )]
        IAsyncResult BeginGetAllBook( AsyncCallback callback, object state );

        IEnumerable<Book> EndGetAllBook( IAsyncResult asyncResult ); 
    }
برای پیاده سازی متد‌های Async به این روش باید دو متد داشته باشیم. یکی به عنوان شروع عملیات و دیگری اتمام. دقت کنید نام گذاری به صورت Begin و End کاملا اختیاری است و برای خوانایی بهتر از این روش نام گذاری استفاده می‌کنم. متدی که به عنوان شروع عملیات استفاده می‌شود باید حتما OperationContractAttribute رو داشته باشد و مقدار خاصیت AsyncPattern اون هم true باشد. همان طور که می‌بیند این متد دارای 2 آرگومان وروردی است. یکی از نوع AsyncCallback و دیگری از نوع object. تمام متد‌های Async به این روش باید این دو آرگومان ورودی را حتما داشته باشند. خروجی این متد حتما باید از نوع IAsyncResult باشد. متد دوم که به عنوان اتمام عملیات استفاده می‌شود نباید OperationContractAttribute را داشته باشد. ورودی اون هم فقط یک آرگومان از نوع IAsyncResult است. خروجی اون هم هر نوعی که سمت کلاینت احتیاج دارید می‌تونه باشه . در صورت عدم رعایت نکات فوق، هنگام ساخت  ChannelFactory یا خطا روبرو خواهید شد. اگر نیاز به پارامتر دیگری هم داشتید باید آن‌ها را قبل از این دو پارامتر قرار دهید. برای مثال:
[OperationContract]
IEnumerable<Book> GetAllBook(int code , AsyncCallback callback, object state );
قبل از پیاده سازی سرویس باید ابتدا یک AsyncResult سفارشی بسازیم. ساخت AsyncResult سفارشی بسیار ساده است. کافی است کلاسی بسازیم که اینترفیس IAsyncResult را به ارث ببرد.
 public class CompletedAsyncResult<TEntity> : IAsyncResult where TEntity : class , new()
    {
        public IList<TEntity> Result
        {
            get
            {
                return _result;
            }
            set
            {
                _result = value;
            }
        }
        private IList<TEntity> _result;

        public CompletedAsyncResult( IList<TEntity> data )
        {
            this.Result = data;
        }

        public object AsyncState
        {
            get
            {
                return ( IList<TEntity> )Result;
            }
        }

        public WaitHandle AsyncWaitHandle
        {
            get
            {
                throw new NotImplementedException();
            }
        }

        public bool CompletedSynchronously
        {
            get
            {
                return true;
            }
        }

        public bool IsCompleted
        {
            get
            {
                return true;
            }
        }
    }
در کلاس بالا یک خاصیت به نام Result درنظر گرفتم که لیستی از نوع TEntity است.(TEntityبه صورت generic تعریف شده و نوع ورودی آن هر نوع کلاس غیر abstract می‌تواند باشد). این کلاس برای تمام سرویس‌های Async یک پروژه مورد استفاده قرار خواهد گرفت برای همین ورودی آن به صورت generic در نظر گرفته شده است.
#پیاده سازی سرویس
 public class BookService : IBookService
    {
        public BookService()
        {
            ListOfBook = new List<Book>();
        }

        public List<Book> ListOfBook
        {
            get;
            private set;
        }

        private List<Book> CreateListOfBook()
        {
            Parallel.For( 0, 10000, ( int counter ) =>
            {
                ListOfBook.Add( new Book()
                {
                    Code = counter,
                    Title = String.Format( "Book {0}", counter ),
                    Author = "Masoud Pakdel"
                } );
            } );

            return ListOfBook;
        }

        public IAsyncResult BeginGetAllBook( AsyncCallback callback, object state )
        {
            var result = CreateListOfBook();
            return new CompletedAsyncResult<Book>( result );
        }

        public IEnumerable<Book> EndGetAllBook( IAsyncResult asyncResult )
        {
            return ( ( CompletedAsyncResult<Book> )asyncResult ).Result;
        }
    }
*در متد BeginGetAllBook ابتدا به تعداد 10,000 کتاب در یک لیست ساخته می‌شوند و بعد این لیست در کلاس CompletedAsyncResult که ساختیم به عنوان ورودی سازنده پاس داده می‌شوند. چون CompletedAsyncResult از IAsyncResult ارث برده است پس return آن به عنوان خروجی مانعی ندارد. با فراخوانی متد EndGetAllBook سمت کلاینت  مقدار asyncResult به عنوان خروجی برگشت داده می‌شود. به عملیات casting برای دستیابی به مقدار Result در CompletedAsyncResult دقت کنید.
#کد‌های سمت کلاینت:
اکثر برنامه نویسان با استفاده از روش AddServiceReference یک سرویس کلاینت در اختیار خواهند داشت که با وهله سازی از این کلاس یک ChannelFactory ایجاد می‌شود. در این پست به جای استفاده از Code Generation توکار دات نت برای ساخت ChannelFactory از روش دیگری استفاده خواهیم کرد. به عنوان برنامه نویس باید بدانیم که در پشت پرده عملیات ساخت ChannelFactory چگونه است.
 روش AddServiceReference
بعد از اضافه شدن سرویس سمت کلاینت کد‌های زیر برای سرویس Book به صورت زیر تولید می‌شود.
[System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
    public partial class BookServiceClient : System.ServiceModel.ClientBase<UI.BookService.IBookService>, UI.BookService.IBookService {
        
        public BookServiceClient() {
        }
        
        public BookServiceClient(string endpointConfigurationName) : 
                base(endpointConfigurationName) {
        }
        
        public BookServiceClient(string endpointConfigurationName, string remoteAddress) : 
                base(endpointConfigurationName, remoteAddress) {
        }
        
        public BookServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : 
                base(endpointConfigurationName, remoteAddress) {
        }
        
        public BookServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : 
                base(binding, remoteAddress) {
        }
        
        public UI.BookService.Book[] BeginGetAllBook() {
            return base.Channel.BeginGetAllBook();
        }
    }
همانطور که می‌بینید سرویس بالا از کلاس ClientBase ارث برده است. ClientBase دارای خاصیتی به نام ChannelFactory است که فقط خواندنی می‌باشد. با استفاده از مقادیر EndPointConfiguration یک وهله از کلاس ChannelFactory با توجه به مقدار generic کلاس clientBase ایجاد خواهد شد. در کد زیر مقدار TChannel برابر IBookService است:
System.ServiceModel.ClientBase<UI.BookService.IBookService>
وهله سازی از ChannelFactory به صورت دستی
یک پروژه ConsoleApplication سمت کلاینت ایجاد کنید. برای فراخوانی متد‌های سرویس سمت سرور باید ابتدا تنظیمات EndPoint رو به درستی انجام دهید. سپس با استفاده از EndPoint به راحتی می‌توانیم Channel مربوطه را بسازیم.
کلاسی به نام ServiceMapper ایجاد می‌کنیم که وظیفه آن ساخت ChannelFactory به ازای درخواست‌ها است.
public class ServiceMapper<TChannel>
    {
        public static TChannel CreateChannel()
        {
            TChannel proxy;

            var endPointAddress = new EndpointAddress( "http://localhost:7000/" + typeof( TChannel ).Name.Remove( 0, 1 ) + ".svc" );

            var httpBinding = new BasicHttpBinding();
            
            ChannelFactory<TChannel> factory = new ChannelFactory<TChannel>( httpBinding, endPointAddress );

            proxy = factory.CreateChannel();

            return proxy;
        }
    }
در متد CreateChannel یک وهله از کلاس EndPointAddress ایجاد شده است. پارامتر ورودی آن آدرس سرویس هاست شده می‌باشد برای مثال:

"http://localhost:7000/" +  "BookService.svc"
دستور Remove برای حذف I از ابتدای نام سرویس است. پارامتر‌های ورودی برای سازنده کلاس ChannelFactory ابتدا یک نمونه از کلاس BasicHttpBinding می‌باشد. می‌توان از WSHttpBinding یا NetTCPBinding یا WSDLHttpBinding هم استفاده کرد. البته هر کدام از انواع Binding‌ها تنظیمات خاص خود را می‌طلبد که در مقاله ای جداگانه بررسی خواهم کرد. پارامتر دوم هم EndPoint ساخته شده می‌باشد. در نهایت با دستور CreateChannel عملیات ساخت Channel به پایان می‌رسد.

بعد از اعمال تغییرات زیر در فایل Program پروژه Console و اجرای آن، خروجی به صورت زیر می‌باشد.
  var channel = ServiceMapper<Contract.IBookService>.CreateChannel();
            channel.BeginGetAllBook( new AsyncCallback( ( asyncResult ) => 
            {
                channel.EndGetAllBook( asyncResult ).ToList().ForEach( _record => 
                {
                    Console.WriteLine( _record.Title );
                } );
            } ) , null );
            Console.WriteLine( "Loading..." );
            Console.ReadLine();
همان طور که می‌بینید ورودی متد BeginGtAllBook یک AsyncCallback است که در داخل آن متد EndGetAllBook صدا زده شده است. مقدار برگشتی متد EndGetAllBook خروجی مورد نظر ماست.
خروجی : 


نکته: برای اینکه مطمئن شوید که سرویس مورد نظر در آدرس "http"//localhost:7000/" هاست شده است(یعنی همان آدرسی که در EndPointAddress از آن استفاه کردیم) کافیست از پنجره Project Properties  برای پروژه سرویس وارد برگه Web شده و از بخش Servers گزینه Use Visual Studio Development Server و Specific Port 7000 رو انتخاب کنید.

 
نظرات اشتراک‌ها
بررسی وضعیت فعلی پروژه Roslyn
کامپایلر سی‌شارپ با ++C نوشته شده. الان این کامپایلر و مابقی کامپایلرهای دات نتی رو با خود دات نت و سی‌شارپ بازنویسی کرده‌اند؛ تحت پروژه‌ای به نام Roslyn. مزیت آن امکان استفاده وسیع از این کامپایلر به صورت سرویس به برنامه نویس‌های دات نت است و همچنین داخل خود VS.NET برای بهبود عملکرد IDE، کارهای Refactoring و آنالیزهای پیشرفته کدها.
مطالب
دسترسی به Collectionها در یک ترد دیگر در WPF
اگر در WPF سعی کنیم آیتمی را به مجموعه اعضای یک Collection مانند یک List یا ObservableCollection از طریق تردی دیگر اضافه کنیم، با خطای ذیل متوقف خواهیم شد:
 This type of CollectionView does not support changes to its SourceCollection
from a thread different from the Dispatcher thread
راه حلی که برای آن تا دات نت 4 در اکثر سایت‌ها توصیه می‌شد به نحو ذیل است:
Adding to an ObservableCollection from a background thread


مشکل!
اگر همین برنامه را که برای دات نت 4 کامپایل شده‌است، بر روی سیستمی که دات نت 4.5 بر روی آن نصب است اجرا کنیم، برنامه با خطای ذیل متوقف می‌شود:
 System.InvalidOperationException: This exception was thrown because the generator for control
'System.Windows.Controls.ListView Items.Count:62' with name '(unnamed)' has received sequence of
CollectionChanged events that do not agree with the current state of the Items collection.
The following differences were detected:  Accumulated count 61 is different from actual count 62.


مشکل از کجاست؟
در دات نت 4 و نیم، دیگر نیازی به استفاده از کلاس MTObservableCollection یاد شده نیست و به صورت توکار امکان کار با Collectionها از طریق تردی دیگر میسر است. فقط برای فعال سازی آن باید نوشت:
 private static object _lock = new object();
//...
BindingOperations.EnableCollectionSynchronization(persons, _lock);
پس از اینکه برای نمونه، مجموعه‌ی فرضی persons وهله سازی شد، تنها کافی است متد جدید EnableCollectionSynchronization بر روی آن فراخوانی شود.


برای برنامه‌ی دات نت 4 ایی که قرار است در سیستم‌های مختلف اجرا شود چطور؟

در اینجا باید از Reflection کمک گرفت. اگر متد EnableCollectionSynchronization بر روی کلاس BindingOperations یافت شد، یعنی برنامه‌ی دات نت 4، در محیط جدید در حال اجرا است:
public static void EnableCollectionSynchronization(IEnumerable collection, object lockObject)
{
      MethodInfo method = typeof(BindingOperations).GetMethod("EnableCollectionSynchronization",
             new Type[] { typeof(IEnumerable), typeof(object) });
      if (method != null)
      {
         method.Invoke(null, new object[] { collection, lockObject });
      }
}
در این حالت فقط کافی است این متد جدید یافت شده را بر روی Collection مدنظر فراخوانی کنیم.
همچنین اگر بخواهیم کلاس MTObservableCollection معرفی شده را جهت سازگاری با دات نت 4 و نیم به روز کنیم، به کلاس ذیل خواهیم رسید. این کلاس با دات نت 4 و 4.5 سازگار است و جهت کار با ObservableCollectionها از طریق تردهای مختلف تهیه شده‌است:
using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Windows.Data;
using System.Windows.Threading;

namespace WpfAsyncCollection
{
    public class AsyncObservableCollection<T> : ObservableCollection<T>
    {
        public override event NotifyCollectionChangedEventHandler CollectionChanged;
        private static object _syncLock = new object();

        public AsyncObservableCollection()
        {
            enableCollectionSynchronization(this, _syncLock);
        }

        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            using (BlockReentrancy())
            {
                var eh = CollectionChanged;
                if (eh == null) return;

                var dispatcher = (from NotifyCollectionChangedEventHandler nh in eh.GetInvocationList()
                                  let dpo = nh.Target as DispatcherObject
                                  where dpo != null
                                  select dpo.Dispatcher).FirstOrDefault();

                if (dispatcher != null && dispatcher.CheckAccess() == false)
                {
                    dispatcher.Invoke(DispatcherPriority.DataBind, (Action)(() => OnCollectionChanged(e)));
                }
                else
                {
                    foreach (NotifyCollectionChangedEventHandler nh in eh.GetInvocationList())
                        nh.Invoke(this, e);
                }
            }
        }

        private static void enableCollectionSynchronization(IEnumerable collection, object lockObject)
        {
            var method = typeof(BindingOperations).GetMethod("EnableCollectionSynchronization", 
                                    new Type[] { typeof(IEnumerable), typeof(object) });
            if (method != null)
            {
                // It's .NET 4.5
                method.Invoke(null, new object[] { collection, lockObject });
            }
        }
    }
}
در این کلاس، در سازنده‌ی آن متد عمومی enableCollectionSynchronization فراخوانی می‌شود. اگر برنامه در محیط دات نت 4 فراخوانی شود، تاثیری نخواهد داشت چون method در حال بررسی نال است. در غیراینصورت، برنامه در حالت سازگار با دات نت 4.5 اجرا خواهد شد.
مطالب
چگونگی دسترسی به فیلد و خاصیت غیر عمومی
یک از ابتدایی‌ترین مواردی که در یادگیری دات نت آموزش داده می‌شود مباحث مربوط به کپسوله سازی است. برای مثال فیلد‌ها و خواص Private که به صورت خصوصی هستند یا Protected هستند از خارج کلاس قابل دسترسی نیستند. برای دسترسی به این کلاس‌ها باید از خواص یا متدهای عمومی استفاده کرد.
public class Book
    {
        private int code = 10;        

        public int GetCode()
        {
            return code;
        }
    }
یا فیلدها و خواصی که به صورت فقط خواندنی هستند،(RealOnly) امکان تغییر مقدار برای اون‌ها وجود ندارد. برای مثال کد پایین کامپایل نخواهد شد.
public class Book
    {
        private readonly int code = 10;        

        public int GetCode()
        {
            return code = 20;
        }        
    }
اما در دات نت با استفاده از Reflection‌ها می‌تونیم تمام قوانین بالا رو نادیده بگیریم. یعنی می‌تونیم هم به خواص و فیلد‌های غیر عمومی کلاس دسترسی پیدا کنیم و هم می‌تونیم مقدار فیلدهای فقط خواندنی رو تغییر بدیم. به مثال‌های زیر دقت کنید.
#مثال اول
using System.Reflection;

 public class Book
 {
        private int code = 10;
 }

 public class Program
 {
        static void Main( string[] args )
        {
            Book book = new Book();
            var codeField = book.GetType().GetField( "code", BindingFlags.NonPublic | BindingFlags.Instance );
            codeField.SetValue( book, 20 );
            var value = codeField.GetValue( book );
        }
    }
ابتدا یک کلاس که دارای یک متغیر به نام کد است ساخته ایم که مقدار 10 را دارد. فیلد به صورت private  است. بعد از اجرا به راحتی مقدار Code را به دست می‌آوریم.


حتی امکان تغییر مقدار فیلد private هم امکان پذیر است.

#مثال دوم.
در این مثال قصد داریم مقدار یک فیلد، از نوع فقط خواندنی رو تغییر دهیم.
using System.Reflection;

 public class Book
 {
        private readonly int code = 10;
 }

 public class Program
 {
        static void Main( string[] args )
        {
            Book book = new Book();
            var codeField = book.GetType().GetField( "code", BindingFlags.NonPublic | BindingFlags.Instance );
            codeField.SetValue( book, 50);
            var value = codeField.GetValue( book );
        }
    }
بعد از اجرا مقدار متغیر code به 50 تغییر می‌یابد.

مطالب تکمیلی



نظرات مطالب
امکان تعریف اعضای static abstract در اینترفیس‌های C# 11
پشتیبانی از ریاضیات جنریک در C# 11

در C# 11، امکان انجام عملیات ریاضی بر روی نوع‌های جنریک میسر شده‌است که قسمتی از آن‌را در مطلب جاری مطالعه کردید. این ویژگی به همراه دو مزیت زیر است:
- اکنون اعضای استاتیک اینترفیس‌ها می‌توانند abstract هم باشند؛ یعنی کلاس‌های پیاده ساز آن‌ها باید این اعضای استاتیک را پیاده سازی کنند.
-  امکان تعریف عملگرهای استاتیک ریاضی در اینترفیس‌ها ممکن شده‌است:
 static T Add<T>(T left, T right) where T : INumber<T> => left + right;
در این مثال، نوع T، تنها می‌تواند از نوع <INumber<T باشد که یکی از اینترفیس‌های جدید NET 7. است. این اینترفیس نیز پیاده سازی کننده‌ی IAdditionOperators است که در آن امکان دسترسی به عملگر + وجود دارد. متد فوق را می‌توان تقریبا توسط تمام نوع‌های ریاضی توکار دات نت مورد استفاده قرار داد؛ از این جهت که تعاریف آن‌ها نیز در دات نت 7 برای پشتیبانی از INumber به‌روز رسانی شده‌اند.
یکی از مهم‌ترین مزیت‌های چنین امکانی، کاهش تعداد overload هایی است که باید توسعه دهندگان کتابخانه‌ها برای پشتیبانی از انواع و اقسام نوع‌های ریاضی ارائه دهند.
 

تغییرات API دات نت 7 در جهت پشتیبانی از ریاضیات جنریک

در مطلب جاری با اینترفیس جدید INumber آشنا شدیم که توسط آن مفاهیمی مانند صفر و یک و همچنین سربارگذاری عملگرهای ریاضی میسر شده‌است. تعداد این اینترفیس‌های توکار در دات نت 7، فراتر از یک مورد فوق است. برای مثال اینترفیس جدید IMinMaxValue امکان دسترسی به T.MinValue و T.MaxValue را میسر می‌کند.
یک مثال: امضای نوع Int32 در دات نت 7 به صورت زیر در آمده‌است:
public readonly struct Int32 : 
  IComparable, 
  IComparable<int>, 
  IConvertible, 
  IEquatable<int>, 
  IFormattable, 
  IParsable<int>, 
  ISpanFormattable, 
  ISpanParsable<int>, 
  IAdditionOperators<int, int, int>, 
  IAdditiveIdentity<int, int>, 
  IBinaryInteger<int>, 
  IBinaryNumber<int>, 
  IBitwiseOperators<int, int, int>, 
  IComparisonOperators<int, int, bool>, 
  IEqualityOperators<int, int, bool>, 
  IDecrementOperators<int>, 
  IDivisionOperators<int, int, int>, 
  IIncrementOperators<int>, 
  IModulusOperators<int, int, int>, 
  IMultiplicativeIdentity<int, int>, 
  IMultiplyOperators<int, int, int>, 
  INumber<int>, 
  INumberBase<int>, 
  ISubtractionOperators<int, int, int>, 
  IUnaryNegationOperators<int, int>, 
  IUnaryPlusOperators<int, int>, 
  IShiftOperators<int, int, int>, 
  IMinMaxValue<int>, 
  ISignedNumber<int>
یعنی تمام نوع‌های ریاضی توکار دات نت 7 از ریاضیات جنریک پشتیبانی می‌کنند. البته نوع‌ها زیر هنوز از یک چنین پشتیبانی برخوردار نیستند:
- System.Half
- System.Numerics.BigInteger
- System.Numerics.Complex
- System.Runtime.InteropServices.NFloat
- System.Int128
- System.UInt128

نوع‌های Int128 و UIn128 جزو تازه‌های دات نت 7 هستند (128-bit signed integer و 128-bit unsigned integer).

البته عموم ما از همان اینترفیس INumber و IBinaryInteger استفاده خواهیم کرد که خود آن نیز به صورت زیر تعریف شده‌است:
public interface INumber<TSelf> : 
IComparable, 
IComparable<TSelf>, 
IEquatable<TSelf>, 
IFormattable, 
IParsable<TSelf>, 
ISpanFormattable, 
ISpanParsable<TSelf>, 
IAdditionOperators<TSelf, TSelf, TSelf>, 
IAdditiveIdentity<TSelf, TSelf>, 
IComparisonOperators<TSelf, TSelf, bool>, 
IEqualityOperators<TSelf, TSelf, bool>, 
IDecrementOperators<TSelf>, 
IDivisionOperators<TSelf, TSelf, TSelf>, 
IIncrementOperators<TSelf>, 
IModulusOperators<TSelf, TSelf, TSelf>, 
IMultiplicativeIdentity<TSelf, TSelf>, 
IMultiplyOperators<TSelf, TSelf, TSelf>, 
INumberBase<TSelf>, 
ISubtractionOperators<TSelf, TSelf, TSelf>, 
IUnaryNegationOperators<TSelf, TSelf>, 
IUnaryPlusOperators<TSelf, TSelf> where TSelf : INumber<TSelf>?
اشتراک‌ها
یک ویرایشگر تمام عیار برای طراحان وب!

با کلیک کردن روی دکمه «Launch the Editor» یک محیط ساده و سریع برای ویرایش فایل‌های HTML، Js و Css به همراه امکان نمایش آنلاین نتایج برای شما فراهم می‌شود. نکته جالب دسترسی ساده به بسیاری از کتابخانه‌های معروف جاوااسکریپت است که به صورت خودکار به پروژه‌های شما اضافه می‌شوند. مدیریت نسخه‌های مختلف فایلها و ... 

یک ویرایشگر تمام عیار برای طراحان وب!