الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

Linq: Deferred Execution

بدأه Mohammad Elsheimy في 23 ديسمبر 2008 · 2 رد · 437 مشاهدة · في Microsoft Visual C#.NET
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

تعتمد LINQ في الاستعلامات الخاصة بها على تقنية وهي Deferred Execution (التنفيذ المؤجل) ومعنى هذه التقنية أن الاستعلام لن ينفذ إلا حين يقوم المبرمج بطلب النتائج من الاستعلام.

لاحظ المثال:

static void TryLinq()
{
	int i = 0;
	int[] numbers = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };


	// fake values for the query only (10 values) 

	var result = from n in numbers select Increment(ref i); 

	Console.WriteLine("After query i = {0}", i); // i still 0 

	Console.WriteLine(); 

	Console.WriteLine("Enumerating results:");
	foreach (var v in result)
	{
		Console.WriteLine("v = {0},\ti = {1}", v, i);
		// i is incremented every loop
	} 

	Console.WriteLine("Press any key to continue . . .");
	Console.ReadKey(true); 

	// Result:- 

	// After query i = 0
	// 
	// Enumerating results:
	// v = 1,  i = 1
	// v = 2,  i = 2
	// .............
	// v = 9,  i = 9
	// v = 10, i = 10 

	// What you get?
	// Deferred-Execution / Lazy-Execution
	// - Query doesn't execute until you begin retrieving it's results.
	// - Every time you try get a value the query executes on this value only.
}

static int Increment(ref int i) { return ++i; }

نلاحظ في هذا المثال أنه يجب أن يكون المتغير i يساوي 10 (وذلك بعد إضافته كمدخلات للدالة Increment إضافته 10 مرات والتي تزيد عليه 1 كل مرة)

ولكن بعد تنفيذ الأمر تبقى i تساوي 0 كأن الاستعلام لم ينفذ.

أما أثناء عمل loop على النتائج زادت i كل مرة 1.

وذلك هو Deferred Execution.

  • الـ Query لا يتم تنفيذها إلا عند طلب النتائج الخاصة بها.
  • كل مرة في الـ loop تقوم الـ Query بالتنفيذ فقط على العنصر المطلوب
    ولهذا نجد أن العنصر i يزيد كل مرة كأن الـ quey تنفذ كل مرة على عنصر واحد فقط

كيف نقوم بتنفيذ الاستعلام في نفس اللحظة:

static void TryLinq()
{
	int i = 0;
	int[] numbers = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	// fake values for the query only (10 values) 

	var result = (from n in numbers select Increment(ref i)).ToList();
	// The last call tries to get the value immediately. 

	Console.WriteLine("After query i = {0}", i); // i is 10 

	Console.WriteLine(); 

	Console.WriteLine("Enumerating results:");
	foreach (var v in result)
	{
		Console.WriteLine("v = {0},\ti = {1}", v, i);
		// i still 10 every loop
	} 

	Console.WriteLine("Press any key to continue . . .");
	Console.ReadKey(true); 

	// Result:- 

	// After query i = 10
	// 
	// Enumerating results:
	// v = 1,  i = 10
	// v = 2,  i = 10
	// .............
	// v = 9,  i = 10
	// v = 10, i = 10 

	// What you get?
	// Deferred-Execution / Lazy-Execution
	// - Query doesn't execute until you begin retrieving it's results.
	// - Every time you try get a value the query executes on this value only.
	// - You can immediate-execute the query by calling some conversation methods like ToList or ToQuery.
} 

static int Increment(ref int i) { return ++i; }

نلاحظ في هذا الكود أن استخدامنا لأحد الدالات ToList أو ToArray فإننا بذلك نقوم بطلب تحويل النتائج إلى عنصر من نوع List او مصفوفة Array وبذلك قإننا نطلب من الاستعلام أن ينفذ في نفس اللحظة كي نستطيع تحويله.

وبذلك نجد أن i بعد الاستعلام يكون 10

وأيضا نجد أنه مع عملية loop أن i ثابت على رقم 10.

أرجوا ان أكون قد استطعت الإفادة

لقراءة الموضوع بالكامل:

http://m-elsheimy.spaces.live.com/blog/cns...6!422.entry

#2

موضوع جميل ، مشكور اخي

ولو سمحت لي ، احب اضيف ان المتغير result في المثال الأول يسمى متغير الأستعلام (Query Variable) ، لأنه يخزن الأستعلام نفسه عوضاً عن نتيجة الأستعلام.

وهذا مثال يوضح نفس الفكرة:

List<int> list = new List<int>(new int[] { 1, 2, 3, 4, 5 });
			var result = from n in list select n;

			foreach (int n in result)
			{
				Console.WriteLine(n);
			}
			//Outputs:- 1 2 3 4 5

			list.Add(9);
			foreach (int n in result)
			{
				Console.WriteLine(n);
			}
			//Outputs:- 1 2 3 4 5 9

نلاحظ ان 9 ظهرت في foreach الثانية بدون ان نعيد الأستعلام.

لكن المتغير result في المثال ثاني لا يسمى متغير الأستعلام لأنه يحتوي نتيجة الأستعلام

List<int> list = new List<int>(new int[] { 1, 2, 3, 4, 5 });
			var result = (from n in list select n).ToList();

			foreach (int n in result)
			{
				Console.WriteLine(n);
			}
			//Outputs:- 1 2 3 4 5

			list.Add(9);
			foreach (int n in result)
			{
				Console.WriteLine(n);
			}
			//Outputs:- 1 2 3 4 5

[وسط]لا اله الا انت سبحانك انى كنت من الظالمين

[/وسط]

#3

صح والنوع ده اسمه Query Reuse ودي واحدة تانية من خصائص LINQ شكرا لك أخي حسن

مواضيع مشابهة