حسین احمدی
بنیانگذار توسینسو و برنامه نویس و توسعه دهنده ارشد وب

آموزش کار با Object Context Boundry ها در سی شارپ

پیش از این در مورد AppDomain ها صحبت کردیم و گفتیم هر برنامه ای که توسط CLR اجرا می شود یک AppDomain مختص به خود دارد، در حقیقت CLR به جای ایجاد یک Process برای هر برنامه، یک AppDomain برای آن برنامه ایجاد می کند. AppDomain ها داخل Process ها ایجاد می شوند و هر Process می تواند شامل چندین AppDomain باشد.

دوره های شبکه، برنامه نویسی، مجازی سازی، امنیت، نفوذ و ... با برترین های ایران

اما شاید جالب باشد که بدانید خود AppDomain ها هم می توانند به زیر قسمت هایی تقسیم شوند که اصطلاحاً به آن ها Object Context Boundry می گویند. زمانی که یک AppDomain ایجاد می شود، به صورت پیش فرض یک Object Context Boundry پیش فرض ایجاد شده می شود و می توان بر اساس نیاز Context Boundry های دیگری نیز ایجاد کرد. معمولاً Context Boundry ها برای اشیاء ای ایجاد می شوند که نیازمندهای خاصی در زمان اجرا دارند و باید در یک محیط ایزوله در زمان اجرا ایجاد شوند.

این قابلیت به CLR این اجازه را می دهد تا عملیات اجرای متدها برای شئ ایجاد شده در یک Context مشخص را بر اساس Context ایجاد شده مدیریت کند. برای مثال، زمانی که شما شئ ای ایجاد می کنید و نیاز هست که شئ ایجاد شده به صورت خودکار مسائل Thread Safety را مد نظر بگیرد (استفاده از SynchronizationAttribute)، CLR یک Context مجزا برای شئ ایجاد شده در نظر میگیرد.

همانطور که گفتیم هر AppDomain شامل یکسری Context است که در زمان اجرای برنامه یک Context پیش فرض به نام Context 0 برای AppDomain ایجاد می شود و کلیه شئ های ایجاد شده در دات نت به صورت پیش فرض در این Context قرار میگیرند. در صورتی که شئ ای با نیازمندهای خاص ایجاد شود، CLR برای آن یک Context جدید ایجاد می کند. در تصویر زیر می توانید نمایی کلی از یک Process به همراه AppDomain های آن و Context های داخل AppDomain ها مشاهده کنید:

img1


نوع های Context-Agile و Context-Bound

زمانی که شما یک Data Type جدید مانند یک کلاس ایجاد می کند و به صورت پیش فرض هیچ تغییری بر روی آن داده نمی شود و نیازی به Context مجزا ندارد، اصطلاحاً به این نوع داده Context-Agile Type گفته می شود. ایجاد این نوع از کلاس ها بسیار ساده است که تا به حال بارها کلاس هایی از نوع را ایجاد کرده ایم:

// Context-Agile class
public class Person
{
}

ایجاد اشیاء Context-Bound

کلیه اشیاء ای که از روی این کلاس ساخته می شوند در Context 0 قرار میگیرند. اما کلاس هایی که نیاز به Context Boundry های مجزا دارند، می بایست از کلاس System.ContextBoundObject مشتق شوند تا در زمان ایجاد شئ برای آن ها Context مجزایی در نظر گرفته شوند. به این دست کلاس ها Context-Bound Type گفته می شود. در مثال زیر شئ Person به صورت Context-Bound ایجاد شده است:

public class Person : System.ContextBoundObject
{
}

علاوه بر اینکه اشیاء Context-Bound می بایست از کلاس ContextBoundObject مشتق شوند، استفاده از Attribute هایی که از کلاس ContextAttribute مشتق شده اند بر روی کلاس مورد نیز الزامی است. برای مثال SynchronizationAttribute که در ابتدای این مطلب در مورد آن صحبت کردیم از کلاس ContextAttribute مشتق شده است و در صورت قرار گرفتن بر روی یک کلاس، آن کلاس می بایست از کلاس ContextBoundObject نیز مشتق شود.با مثالی ادامه می دهیم. فرض کنید کلاسی با نام Person می خواهیم ایجاد کنیم که ماهیت این کلاس Thread Safe است. برای اینکار کلاس مورد نظر را به صورت زیر تعریف می کنیم:

[Synchronization]
public class Person : ContextBoundObjext
{
}

همانطور که مشاهده می کنید علاوه بر اینکه خصوصیت Synchronization بر روی این کلاس قرار گرفته، همچنین کلاس پایه ContextBoundObject به عنوان کلاس پدر آن در نظر گرفته شده است. در این حالت و در صورتی که شئ جدیدی از روی Person ایجاد کنیم، این شئ در یک Context مجزا ایجاد می شود. همانطور که گفتیم کلاس بالا یک کلاس Thread Safe است، یعنی دسترسی سایر Thread ها به آن باید محدود باشد.

با مشخص کردن کلاس Person به عنوان یک شئ Context-Bound به CLR می گوییم که تخصیص این شئ تنها در یک Context مجزا امکان پذیر است. در حقیقت Context ایجاد شده Synchronized Context است و امکان ایجاد شئ در یک Context که Unsynchronized است وجود ندارد، این موضوع این اطمینان را به ما می دهد که عملیات های انجام شده و دسترسی ها به شئ مورد نظر هیچ گونه مشکلی برای ما ایجاد نمی کند. پس به طور کلی می توان اینطور گفت که خصوصیت Synchronization بر روی کلاس اشیاء ساخته شده از روی Person را در یک SynchronizedContext ایجاد کرده و مشتق کردن این کلاس از ContextBoundObject این اطمینان را به می دهد که کلاس از Context خود خارج نمی شود.

دسترسی به اطلاعات Context ها

در این قسمت می خواهیم با نحوه دریافت اطلاعات مربوط به یک Context آشنا شویم. در ادامه کلاس Person را که در قسمت قبلی ایجاد کردیم به صورت زیر تغییر می دهیم:

[Synchronization]
public class Person : ContextBoundObject
{
    public Person()
    {
        Console.WriteLine("Object {0} located in Context {1}",this,Thread.CurrentContext.ContextID);
        Console.WriteLine("Context Properties:");
        foreach (var property in Thread.CurrentContext.ContextProperties)
        {
            Console.WriteLine("    " + property.Name);
        }
    }
}

کلاس دیگری نیز با نام Car به صورت زیر ایجاد می کنیم:

public class Car
{
    public Car()
    {
        Console.WriteLine("Object {0} located in Context {1}", this, Thread.CurrentContext.ContextID);
        Console.WriteLine("Context Properties:");
        foreach (var property in Thread.CurrentContext.ContextProperties)
        {
            Console.WriteLine("    " + property.Name);
        }
    }
}

همانطور که از کد نوشته شده می توان حدس زد کلاس Person از نوع Context-Bound و کلاس Car از نوع Context-Agile است. اما یک نکته وجود دارد و آن هم کدی است که در سازنده این کلاس ها نوشته شده. بوسیله خاصیت CurrentContext در کلاس Thread می توان به Context ای که Thread جاری در حال استفاده از آن است دسترسی داشته باشیم. در مثال بالا بوسیله خاصیت ContextID شناسه Context جاری را نمایش می دهیم. همچنین بوسیله ContextProperties می توان لیست خصوصیات Context را بدست آورده و نمایش داد. در مرحله در متد Main کد زیر را می نویسیم:

var person1 = new Person();
Console.WriteLine("--------------------");
var person2 = new Person();
Console.WriteLine("--------------------");
var car = new Car();

با اجرای کد بالا خروجی زیر نمایش داده می شود:

Object ContextBoundries.Person located in Context 1
Context Properties:
    LeaseLifeTimeServiceProperty
    Synchronization
--------------------
Object ContextBoundries.Person located in Context 2
Context Properties:
    LeaseLifeTimeServiceProperty
    Synchronization
--------------------
Object ContextBoundries.Car located in Context 0
Context Properties:
    LeaseLifeTimeServiceProperty

همانطور که مشاهده می کنید دو شئ ای که از روی کلاس Person ساخته شده است به ترتیب در Context های 1 و 2 ایجاد شده اند، اما شئ ساخته شده از روی کلاس Car در Context 0 که Context پیش فرض است ایجاد شده است.خیلی به ندرت اتفاق می افتد که بخواهیم از Context Boundry ها استفاده کنیم، اما داشتن آشنایی با مفاهیمی مانند Context Boundry ها می تواند در شرایط خاص به کمک ما بیاید. امیدوارم که این مطلب مورد توجه شما دوستان عزیز قرار گرفته باشد.


حسین احمدی
حسین احمدی

بنیانگذار توسینسو و برنامه نویس و توسعه دهنده ارشد وب

حسین احمدی ، بنیانگذار TOSINSO ، توسعه دهنده وب و برنامه نویس ، بیش از 12 سال سابقه فعالیت حرفه ای در سطح کلان ، مشاور ، مدیر پروژه و مدرس نهادهای مالی و اعتباری ، تخصص در پلتفرم دات نت و زبان سی شارپ ، طراحی و توسعه وب ، امنیت نرم افزار ، تحلیل سیستم های اطلاعاتی و داده کاوی ...

نظرات