2009-01-19 68 views
11

想象我有以下幾點:如何LINQ時推遲執行在using語句

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線? 有沒有可以幫助的古魯?

編輯: 注意:此代碼確實工作,我只是不明白如何。

我做了一些閱讀,並在代碼中意識到我已經調用了ToList()擴展方法,當然這些擴展方法枚舉了結果。被選中答案的行爲對於回答的實際問題是完全正確的。

對不起,有任何混淆。

+0

不錯的問題。我被這個炸燬..一個使用(DataContext)爆炸壯觀 – Gishu 2009-01-19 06:52:41

+0

我得到一個ObjectDisposedException「Dispose後訪問的DataContext」。當我嘗試這個。你的MyDataContext是LINQ設計器的自動生成的DataContext嗎?它是否從DataContext繼承? – 2009-01-19 07:44:36

+0

我第三個概念:如果你通過使用「使用」來處理你的datacontext,你將會 - 如果你稍後嘗試使用datacontext,將會得到一個運行時異常。我知道我已經做到了。 – 2009-01-19 23:22:29

回答

12

我希望這樣做根本就行不通; 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; 
     } 
    } 
} 

這就是現在被推遲周圍沒有傳遞數據上下文。

8

我剛貼另一個暫緩執行解決了這個問題here,包括此示例代碼:

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塊。