2015-01-20 44 views
3

生成的調用的數量我注意到我們的應用程序存在一些性能問題,並且已經將它跟蹤到了我們類中ID屬性的調用數量。爲什麼通過LINQ FirstOrDefault或第一個

我已經設置了一個示例來解釋。

我們有兩個類Person和Address。

我創建了10個實例,每個實例都有ID字段(Person_Id,Address_Id)。

在該樣品的情況下,PERSON_ID的1名映射到ADDRESS_ID 1.

爲了鏈接在一起這些I具有在「地址」人的只讀屬性,並返回相關聯的地址對象通過對地址集合執行LINQ查詢。 爲了簡單起見,我返回Address_Id = Person_Id的地址,因爲我在每個列表中有相同數量的項目,這是用於測試的。

public Address Address 
{ 
    get 
    { 
     return Addresses.FirstOrDefault(a => a.Address_Id == Person_Id); 
    } 
} 

PERSON_ID是公共財產與私人支持字段。很簡單。

private int _person_Id; 
public int Person_Id 
{ 
    get 
    { 
     return _person_Id; 
    } 
    set 
    { 
     _person_Id = value; 
    } 
} 

當跟蹤調用Person_Id裏面的次數時,金額總是高於人記錄的數量。在這種情況下,我正在迭代人員記錄列表並輸出人員的姓名和狀態。

foreach (var person in persons) 
{ 
    var name = person.Name; 
    var state = person.Address.State; 
    Console.WriteLine(name + "\t" + state); 
} 

下面是如何調用的數量分解後基於迭代人實體的數量:回顧數學

calls based on # of records

,我們可以看到,添加地址#爲調用目前我們所在的實體以及以上的會增加總人次Person_Id。例如:如果我們有5個人的記錄迭代,有5個電話來獲得人的「地址」屬性,15個電話獲得人的'Person_Id'屬性。 15是(5 + 4 + 3 + 2 + 1),這是對「地址」的呼叫的總和。

我很好奇這些數字來自哪裏。 FirstOrDefault查找。如果我使用單個的通話量要高得多。

如果我不是創建一個局部變量,例如這樣的:

int personId = Person_Id; 

然後在LINQ查詢使用它:

return Addresses.Find(a => a.Address_Id == personId); 

然後調用是1比1 - 我有1調用Address和Person_Id,正如我從LINQ查詢期望的那樣。

有沒有人知道爲什麼這樣的電話充氣?我有興趣瞭解更多,因爲我正在經歷優化過程。

感謝

+0

您的課程鏈接方式存在問題。你應該在person類中創建一個私有地址,當你調用屬性檢查時,如果私有變量爲空,並且它被設置爲你正在查找的地址的id。如果私人不是null,則立即返回。您目前正在循環訪問您要撥打的每個物業'Person.Address' – Franck 2015-01-20 19:40:55

+0

爲什麼當您甚至沒有測試過FirstOrDefault時,您會詢問FirstOrDefault生成的呼叫數量。爲什麼不測試自己? LINQ仍然對personID進行多次調用 - 您沒有優化任何內容。 – Paparazzi 2015-01-20 19:48:12

+0

我應該添加使用Addresses.FirstOrDefault(a => a.Address_Id == Person_Id)並返回Addresses.Find(a => a.Address_Id == Person_Id)產生與Person_Id相同數量的調用。我將示例代碼留在了最初的帖子中,在那裏我已經獲得了「查找」的#並將其更新爲「FirstOrDefault」,以清除可能出現的任何混淆。謝謝 – dunderwood 2015-01-20 19:52:26

回答

7

你基本上說:「對於內Addresses每個地址,判斷該謂詞,直到斷言返回true,此時返回該地址。」

謂詞是lambda表達式,它使用Person_Id屬性,因此每次都必須對其進行評估。

,或者換一種說法,假設你使用普通的方法,而不是爲了lambda表達式創建斷言:

public Address Address 
{ 
    get 
    { 
     Predicate<Address> predicate = new Predicate<Address>(AddressIdMatches); 
     return Addresses.FirstOrDefault(predicate); 
    } 
} 

private boolean AddressIdMatches(Address a) 
{ 
    return a.Address_Id == Person_Id; 
} 

是不是更清晰?該方法將在每個地址中調用一次,並且希望每次調用該方法時都很明顯,它將評估Person_Id。這就是編譯器在使用lambda表達式時基本爲您構建的。

+0

謝謝。我注意到當你提到它時,我從測試中將「查找」留在那裏,並將其更新回「FirstOrDefault」 - 我正在測試它們以查看差異。 – dunderwood 2015-01-20 19:49:25

+0

@dunderwood:好的,我刪除了介紹部分。 – 2015-01-20 19:54:35

0

在問題的背景下,這一lambda表達式:

a => a.Address_Id == Person_Id 

是真的等同於這個lambda表達式:

a => a.Address_Id == this.Person_Id 

你都隱含在lambda捕捉this - 沒有價值this.Person_Id。所以Person_Id屬性獲取器被重複調用,每個被檢查的Addressa

如果你改變了代碼如下:

int personId = Person_Id; 
... 
a => a.Address_Id == personId 

然後你捕捉變量personId相反,它不需要在每次閱讀時間致電Person_Id屬性的getter。

相關問題