3

我正在尝试查找包含 2 个或更多区域成员的所有区域,其中搜索词是字符串值。这是我的代码。在 FindCommmonZones 方法中,当我尝试将 Intersect 的结果转换为 ObservableCollection 时,我得到了一个无效转换的运行时。问题是,有没有更好的方法来做到这一点?作为 FindCommonZones() 参数的字符串数组可以是任意数量的字符串。StackOverflow 有其他一些类似的帖子,但没有一个真正回答我的问题 - 看起来它们都与 SQL 有关。

一些代码:

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;
    }
4

1 回答 1

0

Intersect实际上是Enumerable.Intersect并且正在返回一个IEnumerable<ZoneResult>. 这不能转换为ObservableCollection,因为它不是一个 - 它是两个集合中相交元素的枚举。

但是,您可以从枚举中创建一个新的 ObservableCollection:

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

根据您拥有的元素数量、ZoneResult.Equals实现方式以及您期望的搜索词数量,此实现可能可行,也可能不可行(FindZones乍一看 O(n^4) 似乎有点过于复杂)。如果它似乎是资源消耗或瓶颈,那么是时候优化了;否则,如果它有效,我会不理它。


一个建议的优化可能如下(结合@Keith 建议更改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);
}
于 2012-10-01T16:15:23.740 回答