2012-10-01 45 views
3

我試圖找到所有包含2個或更多區域成員的區域,其中搜索項是字符串值。這是我的代碼。在FindCommmonZones方法中,當我嘗試將一個交集的結果轉換爲一個ObservableCollection時,我得到一個無效轉換的運行時。問題是,有沒有更好的方法來做到這一點?作爲FindCommonZones()的參數的字符串數組可以是任何字符串數。 StackOverflow有一些其他類似的帖子,但沒有真正回答我的問題 - 它看起來像他們都更多地涉及到SQL。如何檢查包含多個值的CONTAINS

一些代碼:

public class Zone 
{ 
    public List<ZoneMember> MembersList = new List<ZoneMember>(); 
    private string _ZoneName; 
    public string zoneName{ get{return _ZoneName;} set{_ZoneName=value;} } 
     public Zone ContainsMember(string member) 
    { 
     var contained = this.MembersList.FirstOrDefault(m => m.MemberWWPN. 
      Contains(member) || m.MemberAlias.Contains(member)); 

     if (contained != null) { return this; } 
     else { return null; } 

    } 

} 

public class ZoneMember 
    // a zone member is a member of a zone 
    // zones have ports, WWPNs, aliases or all 3 
{ 
    private string _Alias = string.Empty; 
    public string MemberAlias {get{return _Alias;} set{_Alias = value; } } 
    private FCPort _Port = null; 
    public FCPort MemberPort { get { return _Port; } set { _Port = value; } } 
    private string _WWPN = string.Empty; 
    public string MemberWWPN { get { return _WWPN; } set { _WWPN = value; } } 
    private bool _IsLoggedIn; 
    public bool IsLoggedIn { get { return _IsLoggedIn; } set { _IsLoggedIn = value; } } 
    private string _FCID; 
    public string FCID {get{return _FCID;} set{ _FCID=value; } } 
} 


private ObservableCollection<ZoneResult> FindCommonZones(string[] searchterms) 
    { 

     ObservableCollection<ZoneResult> tempcollection = 
      new ObservableCollection<ZoneResult>(); 
     //find the zones for the first search term 
     tempcollection = this.FindZones(searchterms[0]); 

     //now search for the rest of the search terms and compare 
     //them to existing result 
     for (int i = 1; i < searchterms.Count(); i++) 
     { 
      // this line gives an exception trying to cast 
      tempcollection = (ObservableCollection<ZoneResult>)tempcollection. 
      Intersect(this.FindZones(searchterms[i])); 

     } 

     return tempcollection; 
    } 
    private ObservableCollection<ZoneResult> FindZones(string searchterm) 
    // we need to track the vsan where the zone member is found 
    // so use a foreach to keep track 
    { 
     ObservableCollection<ZoneResult> zonecollection = new ObservableCollection<ZoneResult>(); 
     foreach (KeyValuePair<int, Dictionary<int, CiscoVSAN>> fabricpair in this.FabricDictionary) 
     { 
      foreach (KeyValuePair<int, CiscoVSAN> vsanpair in fabricpair.Value) 
      { 
       var selection = vsanpair.Value.ActiveZoneset. 
          ZoneList.Select(z => z.ContainsMember(searchterm)). 
           Where(m => m != null).OrderBy(z => z.zoneName); 
       if (selection.Count() > 0) 
       { 

        foreach (Zone zone in selection) 
        { 
         foreach (ZoneMember zm in zone.MembersList) 
         { 
          ZoneResult zr = new ZoneResult(zone.zoneName, 
          zm.MemberWWPN, zm.MemberAlias, vsanpair.Key.ToString()); 
          zonecollection.Add(zr); 
         } 

        } 

       } 
      } 

     } 
     return zonecollection; 
    } 
+1

爲什麼'ContainsMember'返回'Zone'實例?它不應該只是返回'布爾'嗎?然後你的支票變成'return this.MembersList.Any(m => m.MemberWWPN.Contains(member)|| m.MemberAlias.Contains(member)))''。 – Keith

+0

嗯...因爲這是我寫的方式? :)你的代碼更簡單。我認爲我沒有想到回到布爾。謝謝! –

+0

作爲一般規則 - 如果某個類的方法返回該類的父實例,那麼您可能會在某處調用過度複雜的代碼,因爲任何調用該方法的人都始終擁有該實例。如果這是一個新的實例,例如在一個'Copy()'方法中,那麼只有'Zone'上的方法返回類型'Zone'纔有意義。 – Keith

回答

0

Intersect實際上是Enumerable.Intersect,並返回一個IEnumerable<ZoneResult>。這不是castable添加到ObservableCollection,因爲它不是一個 - 它是兩個集合中相交元素的枚舉。

但您可以創建一個從枚舉的ObservableCollection:

tempcollection = new ObservableCollection<ZoneResult>(tempcollection 
    .Intersect(this.FindZones(searchterms[i])); 

取決於你有多少元素都有,如何ZoneResult.Equals實施,以及你希望有多少搜索詞,這個版本可能可能是不可行的(乍一看,FindZones看起來有點過於複雜的O(n^4))。如果它看起來是資源的瓶頸或瓶頸,那麼是時候優化了;否則如果它能工作的話,我會放棄它。


一位代表建議的優化可能是(包含@基思的建議,改變ContainsMember到布爾)以下的 - 雖然它是未經測試,我大概有我的SelectManys錯了,它確實在很大程度上相當於同樣的事情,你希望得到這個想法:

private ObservableCollection<ZoneResult> FindCommonZones(string[] searchterms) 
{ 

    var query = this.FabricDictionary.SelectMany(fabricpair => 
     fabricpair.Value.SelectMany(vsanpair => 
      vsanpair.Value.ActiveZoneSet.ZoneList 
      .Where(z=>searchterms.Any(term=>z.ContainsMember(term))) 
      .SelectMany(zone => 
       zone.MembersList.Select(zm=>new ZoneResult(zone.zoneName, zm.MemberWWPN, zm.MemberAlias, vsanpair.Key.ToString())) 
     ) 
    ) 
    .Distinct() 
    .OrderBy(zr=>zr.zoneName); 

    return new ObservableCollection<ZoneResult>(query); 
} 
+0

謝謝,我會看看。實際上,我不希望超過2或3個搜索詞。你有更好的實現FindZones()的建議嗎?對我來說重要的一點是跟蹤哪些VSAN的區域被發現。這就是爲什麼我使用foreach()。我沒有看到用LINQ做這件事的方法,因爲我會返回不知道它們屬於哪個VSAN的Zone對象。如有必要,我可以提供VSAN類列表。 –

+0

ZoneResult.Equals沒有實現,我想我需要實現它。另外,如果有更好的方法來獲得我想要的結果,我不必按照我設計的方式來完成。 –

+0

我不認爲Intersect會做你想做的事情,除非你實現Equals或提供一個比較器,因爲兩個不同的集合中的相同結果將是兩個不同的對象。 –

相關問題