لتوضيح الأمثلة ، سأستخدم فئة الاختبار ، التي تحتوي على خاصية BlobData التي تُرجع كائنًا من النوع Blob ، والذي يتم إنشاؤه ، وفقًا لمفهوم الأسطورة ، ببطء شديد ، وقد تقرر إنشاؤه بتكاسل.
class Test
{
public Blob BlobData
{
get
{
return new Blob();
}
}
}
التحقق من وجود فارغة
أبسط خيار متاح من الإصدارات الأولى للغة ، هو إنشاء متغير غير مهيأ واختباره بحثًا عن قيمة خالية قبل العودة. إذا كان المتغير فارغًا ، فأنشئ كائنًا وقم بتعيينه لهذا المتغير ، ثم أعده. عند الوصول المتكرر ، سيتم إنشاء الكائن بالفعل وسنعيده على الفور.
class Test
{
private Blob _blob = null;
public Blob BlobData
{
get
{
if (_blob == null)
{
_blob = new Blob();
}
return _blob;
}
}
}
يتم هنا إنشاء كائن من نوع Blob عند الوصول إلى الخاصية لأول مرة. أو لا يتم إنشاؤه إذا لم يكن البرنامج بحاجة إليه لسبب ما في هذه الجلسة.
عامل ثلاثي ؟:
لدى C # عامل تشغيل ثلاثي يسمح لك باختبار شرط ما ، وإذا كان صحيحًا ، فقم بإرجاع قيمة واحدة ، وإذا كانت خاطئة ، فأخرى. يمكننا استخدامه لاختصار الكود وتبسيطه قليلاً.
class Test
{
private Blob _blob = null;
public Blob BlobData
{
get
{
return _blob == null
? _blob = new Blob()
: _blob;
}
}
}
يبقى الجوهر كما هو. إذا لم تتم تهيئة الكائن ، فقم بالتهيئة والعودة. إذا تمت تهيئته بالفعل ، فسنقوم بإعادته على الفور.
باطل
تختلف المواقف ، وقد نواجه ، على سبيل المثال ، حالة تحتوي فيها فئة Blob على عامل تشغيل زائد التحميل ==. للقيام بذلك ، ربما نحتاج إلى إجراء فحص فارغ بدلاً من == null. متوفر بأحدث إصدارات اللغة.
return _blob is null
? _blob = new Blob()
: _blob;
لكن هذا هو كذلك ، استطرادية صغيرة.
عامل الاندماج الصفري ؟؟
عامل التشغيل الثنائي ؟؟ سيساعدنا في تبسيط الكود أكثر.
جوهر عمله على النحو التالي. إذا لم يكن المعامل الأول فارغًا ، فسيتم إرجاعه. إذا كان المعامل الأول فارغًا ، يتم إرجاع الثاني.
class Test
{
private Blob _blob = null;
public Blob BlobData
{
get
{
return _blob ?? (_blob = new Blob());
}
}
}
يجب وضع المعامل الثاني بين قوسين بسبب أولوية العمليات.
عامل التشغيل ؟؟ =
يقدم C # 8 عامل التوحيد الصفري الذي يشبه هذا؟ =
كيف يعمل كما يلي. إذا لم يكن المعامل الأول فارغًا ، فسيتم إرجاعه ببساطة. إذا كان المعامل الأول فارغًا ، فسيتم تعيين قيمة الثاني له ويتم إرجاع هذه القيمة.
class Test
{
private Blob _blob = null;
public Blob BlobData
{
get
{
return _blob ??= new Blob();
}
}
}
هذا سمح لنا بتقليل الكود أكثر قليلاً.
تيارات
إذا كان هناك احتمال أن العديد من سلاسل الرسائل يمكنها الوصول إلى مورد معين في وقت واحد ، فيجب أن نجعله آمنًا. خلاف ذلك ، قد يحدث موقف ، على سبيل المثال ، سيقوم كلا الخيطين بفحص الكائن بحثًا عن فارغ ، وستكون النتيجة خاطئة ، ثم سيتم إنشاء كائنين Blob ، وتحميل النظام مرتين قدر ما أردناه ، بالإضافة إلى أحد هذه العناصر سيتم حفظ الكائنات ، وسيتم فقد الثانية.
class Test
{
private readonly object _lock = new object();
private Blob _blob = null;
public Blob BlobData
{
get
{
lock (_lock)
{
return _blob ?? (_blob = new Blob());
}
}
}
}
يكتسب بيان القفل قفلًا خاصًا بشكل متبادل على الكائن المحدد قبل تنفيذ عبارات معينة ، ثم يحرر القفل. وهو يعادل استخدام System.Threading.Monitor.Enter (...، ...) ؛
كسول <T>
قدم .NET 4.0 فئة Lazy لإخفاء كل هذا العمل القذر عن أعيننا. الآن يمكننا فقط ترك متغير محلي من النوع Lazy. عند الوصول إلى خاصية Value الخاصة بها ، نحصل على كائن من فئة Blob. إذا تم إنشاء الكائن في وقت سابق ، فسيعود على الفور ، وإلا فسيتم إنشاؤه أولاً.
class Test
{
private readonly Lazy<Blob> _lazy = new Lazy<Blob>();
public Blob BlobData
{
get
{
return _lazy.Value;
}
}
}
نظرًا لأن فئة Blob بها مُنشئ بدون معلمات ، يمكن لـ Lazy إنشاؤها في الوقت المناسب دون أي أسئلة. إذا احتجنا إلى تنفيذ بعض الإجراءات الإضافية أثناء إنشاء كائن Blob ، فيمكن لمنشئ الفئة Lazy الرجوع إلى Func <T>
private Lazy<Blob> _lazy = new Lazy<Blob>(() => new Blob());
بالإضافة إلى ذلك ، في المعلمة الثانية للمنشئ ، يمكننا تحديد ما إذا كنا بحاجة إلى أمان الخيط (نفس القفل).
خاصية
الآن دعنا نخفض خاصية القراءة فقط ، لأن C # الحديث يتيح لك القيام بذلك بشكل جيد. في النهاية ، كل شيء يبدو كما يلي:
class Test
{
private readonly Lazy<Blob> _lazy = new Lazy<Blob>();
public Blob BlobData => _lazy.Value;
}
LazyInitializer
يوجد أيضًا خيار عدم التفاف الفصل في غلاف Lazy ، ولكن بدلاً من ذلك استخدم وظيفة LazyInitializer. تحتوي هذه الفئة على طريقة ثابتة واحدة تأكد من التهيئة مع مجموعة من الأحمال الزائدة التي تسمح لك بإنشاء أي شيء ، بما في ذلك أمان الخيط وكتابة رمز مخصص لإنشاء كائن ، ولكن جوهرها الرئيسي هو كما يلي تحقق مما إذا كان الكائن غير مهيأ. إذا لم يكن كذلك ، فقم بالتهيئة. إرجاع كائن. باستخدام هذا الفصل ، يمكننا إعادة كتابة الكود الخاص بنا على النحو التالي:
class Test
{
private Blob _blob;
public Blob BlobData => LazyInitializer.EnsureInitialized(ref _blob);
}
هذا كل شئ. شكرآ لك على أهتمامك.