كيف LINQ تأجيل التنفيذ عندما تكون في العبارة باستخدام

StackOverflow https://stackoverflow.com/questions/456691

سؤال

وتخيل لدي ما يلي:

private IEnumerable MyFunc(parameter a)
{
   using(MyDataContext dc = new MyDataContext)
   {
      return dc.tablename.Select(row => row.parameter == a);
   }
}

private void UsingFunc()
{
   var result = MyFunc(new a());

   foreach(var row in result)
   {
      //Do something
   }
}

واستنادا إلى وثائق وتنفيذ LINQ تأجيل حتى أنا الفعلي تعداد نتيجة، والذي يحدث في الخط في foreach. لكن العبارة باستخدام يجب أن تجبر الكائن التي سيتم جمعها بشكل موثوق في نهاية الدعوة إلى MyFunct ().

وماذا يحدث في الواقع، عندما المدى المتخلص و / أو نتيجة تشغيل؟

والشيء الوحيد الذي يمكنني أن أفكر من هو يحسب التنفيذ المؤجل في وقت الترجمة، بحيث يتم نقل المكالمة الفعلي من قبل المجمع إلى السطر الأول من foreach، مما تسبب في تستخدمها لتنفيذ بشكل صحيح، ولكن لا تعمل حتى خط foreach ؟ هناك جورو هناك الذين يمكن أن تساعد؟

وتحرير: <الإضراب> NOTE: لا عمل، أنا فقط لا يفهمون هذا الرمز كيف

وفعلت بعض القراءة وأدركت في قانون بلدي بأنني قد دعا طريقة تمديد ToList () والتي بالطبع يعدد النتيجة. السلوك الجواب تكتك هو الصحيح تماما عن الإجابة على السؤال الفعلي.

ونعتذر عن أي التباس.

هل كانت مفيدة؟

المحلول

وأتوقع أن ببساطة لا تعمل. يتم تأجيل Select، لذلك تم استهلاكها أية بيانات في هذه المرحلة. ومع ذلك، لأنك قد تخلصت من السياق البيانات (قبل ان يغادر MyFunc)، فإنه لن يكون قادرا على الحصول على البيانات. الخيار الأفضل هو لتمرير السياق البيانات <م> إلى طريقة، بحيث يمكن للمستهلك اختيار مدى الحياة. أيضا، أود أن أوصي IQueryable<T> عودته بحيث يمكن للمستهلك "يؤلف" النتيجة (أي إضافة OrderBy / Skip / Take / Where غيرها، ويكون ذلك يؤثر الاستعلام النهائي):

// this could also be an instance method on the data-context
internal static IQueryable<SomeType> MyFunc(
    this MyDataContext dc, parameter a)
{
   return dc.tablename.Where(row => row.parameter == a);
}

private void UsingFunc()
{
    using(MyDataContext dc = new MyDataContext()) {
       var result = dc.MyFunc(new a());

       foreach(var row in result)
       {
           //Do something
       }
    }
}

تحديث: إذا كنت (تعليق) لا أريد أن تأجيل التنفيذ (أي أنك لا تريد المتصل التعامل مع السياق البيانات)، ثم تحتاج إلى تقييم النتائج. يمكنك القيام بذلك عن طريق الاتصال .ToList() أو .ToArray() على النتيجة للتخفيف من القيم.

private IEnumerable<SomeType> MyFunc(parameter a)
{
   using(MyDataContext dc = new MyDataContext)
   {
      // or ToList() etc
      return dc.tablename.Where(row => row.parameter == a).ToArray();
   }
}

إذا كنت تريد الاحتفاظ بها المؤجلة في هذه الحالة، فأنت بحاجة إلى استخدام "كتلة مكرر":

private IEnumerable<SomeType> MyFunc(parameter a)
{
   using(MyDataContext dc = new MyDataContext)
   {
      foreach(SomeType row in dc
          .tablename.Where(row => row.parameter == a))
      {
        yield return row;
      }
   }
}

ويتم تأجيل هذا الآن دون تمرير السياق البيانات حولها.

نصائح أخرى

ولقد شارك حل آخر مؤجل التنفيذ لهذه المشكلة هنا ، بما في ذلك هذه التعليمات البرمجية:

IQueryable<MyType> MyFunc(string myValue)
{
    return from dc in new MyDataContext().Use()
           from row in dc.MyTable
           where row.MyField == myValue
           select row;
}

void UsingFunc()
{
    var result = MyFunc("MyValue").OrderBy(row => row.SortOrder);
    foreach(var row in result)
    {
        //Do something
    }
}

وطريقة تمديد Use() يعمل أساسا مثل كتلة using المؤجل.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top