2011-05-13 62 views
0

在C#類我有一個名單列表,和兩個不同的干將:添加項目到列表中,而不會影響

private List<A> a; 
public List<A> EveryA 
    { 
     get 
     { 
      if (a == null) a = new List<A>(); 
      return a; 
     } 
    } 
public List<A> FilteredA 
    { 
     get 
     { 
      return EveryA.FindAll(a => a.IsInFilter); 
     } 
    } 

現在我的問題是:如何對語法FilteredA.Add(this);
它編譯並運行,但它不能添加任何項目到任何列表。
更好的編譯器是否必須通知(小)問題?

回答

5

他們是不一樣的名單。這不是編譯器可以檢查你的東西,因爲編譯器不能真正閱讀你的想法。檢查文檔List<T>.FindAll

結果是一個列表,但它不是相同的列表(它怎麼可能?您的原始列表未被過濾!)。

您應該可以將項目添加到由FilteredA返回的列表中,但它們不會顯示在a中。

我建議你使用LINQs Where代替,返回IEnumerable<T>。這樣一來,很明顯的FilteredA的結果不應該被改變,只是遍歷:

public IEnumerable<A> FilteredA 
{ 
    get { return EveryA.Where(a => a.IsInFilter); } 
} 
+1

對於linq的建議+1,如果可以的話,+「另一個1」編譯器不能真正閱讀你的想法。 – phoog 2011-05-13 08:12:55

+0

IEnumerable的建議是非常有用和優雅的,我必須記住這一點。然而,使用Linq的建議對我來說並沒有多大意義。我沒有看到與示例代碼中謂詞的區別?帶「Linq」的 – Gerard 2011-05-13 08:46:03

+0

,我只是指'System.Linq'中提供的擴展方法,即'Where'。在你的例子中與謂詞沒有什麼區別,事實上,我重用了你的謂詞。區別僅在於Linq版本使用懶惰評估。你仍然可以使用你的版本,只是改變返回類型。我從來沒有想到... – 2011-05-13 09:11:53

3

不,爲什麼它應該通知你?這完全沒問題。
FilteredA不返回a而是List<A>的新實例。
FilteredA.Add(this);this添加到此新實例。

看到這個代碼:

var filteredA = FilteredA; 
int count1 = filteredA.Count; 
filteredA.Add(this); 
int count2 = filteredA.Count; 
Assert.AreEqual(count1 + 1, count2); 

這表明,新的項目被添加到列表中。但是對於那些獨立於班級內部列表的新實例。

+0

當然,謝謝。 – Gerard 2011-05-13 08:46:29

3

FindAll返回一個新列表。我想,將新項目添加到新列表中,但不保留對新列表的引用。如果過濾的列表來自方法而不是屬性,則語義會更清晰。

+0

我同意,FilteredA應該是一個方法/函數,而不是一個屬性。 – Jodrell 2011-05-13 08:08:40

+0

爲什麼一個方法會產生更清晰的語義?而且 - 當屬性返回IEnmerable而不是List時,它應該在你看來仍然是一種方法(如果是這樣,爲什麼)? – Gerard 2011-05-13 08:51:33

+0

屬性意味着相當靜態的東西;它應該總是返回相同的東西,用於兩個不同的調用(除非有人在調用之間寫入屬性,當然)。帶有getter副作用的屬性(除了那些與讀取屬性相關的屬性,可能就像日誌記錄或延遲加載一樣)都是令人困惑的,因爲在這種情況下,作爲代碼的作者感到困惑。一個名爲GetFilteredA()的方法看起來更像是它能夠在每次調用時創建一個新對象。是的,IEnumerable返回的方法也應該是一種方法。 – phoog 2011-05-13 14:25:49

2

public List<A> FilteredA返回FindAll方法的一些輸出,作爲List<A>。這不會與EveryA的對象相同,因此當它超出範圍時,您的添加將會丟失。

+0

-1:FindAll不是一種擴展方法。 – phoog 2011-05-13 14:28:12

+0

@phoog,我的不好,修復答案。 – Jodrell 2011-05-13 15:57:25

+0

+1修復答案:) – phoog 2011-05-13 16:37:19

1

這不是一個真正的編譯器問題 - 因爲代碼是有效的,它會編譯得很好。問題更多的是代碼質量級別。爲了抓住這樣的事情,你可以使用像FxCop這樣的工具來分析你的代碼。

這兩種方法都可以看作查詢方法。您不應該將結果公開爲List,而應該是IEnumerable或A []。如果您想要將項目添加到列表中,請使用Add方法執行此操作。

private List<A> items = new List<A>(); 

public IEnumerable<A> EveryA 
{ 
    get { return items; } 
} 

public IEnumerable<A> FilteredA 
{ 
    get { return items.Where(item => item.IsInFilter); } 
} 

public void AddItem(A item) 
{ 
    items.Add(item); 
} 
+0

這是一個不錯的解決方案。儘管如此,我仍然略微偏愛公開名單 EveryA,可能也是一個品味問題? – Gerard 2011-05-13 08:48:45