从 List<KeyValuePair<string,string>> 返回匹配
Posted
技术标签:
【中文标题】从 List<KeyValuePair<string,string>> 返回匹配【英文标题】:Returning a match from a List<KeyValuePair<string,string>> 【发布时间】:2010-12-20 02:11:55 【问题描述】:我目前有一个类使用KeyValuePair
和List
来存储音轨集合,格式为 Key = track, Value = Artist。
我正在尝试提供一种搜索特定曲目的方法,如果有任何匹配项,则返回整个匹配的 CD。
这是我目前的尝试:
public CompilationCD FindTrackInComCD(string track)
CompilationCD temp = new CompilationCD();
List<CD> tempComCols = _cdCollection.FindAll(delegate(CD cd)
return cd.GetType() == temp.GetType(); );
foreach (KeyValuePair<string, string> comCD in tempComCols)
if (comCD.Key.Contains(track))
return comCD;
throw new ArgumentException("No matches found");
我有一个 CD 类型的 CD (List<CD>
) 集合,因此我通过将其与临时列表进行比较来创建一个适当类型的新 List<>
。
编译时出现以下错误:
Cannot convert type 'CDCollection.CD' to System.Collections.Generic.KeyValuePair<string,string>'
Cannot implicitly convert type 'System.Collections.Generic.KeyValuePair<string,string>'
(CDCollection 是我的项目命名空间,CD/CompilationCD 是类)
抱歉,这个问题似乎与我之前提出的问题类似。我尝试使用之前给出的方法,但我有点难过;我没有经常使用List<>
或KeyValuePair
。
这是 CD 类:
using System;
使用 System.Collections; 使用 System.Collections.Generic; 使用 System.Linq; 使用 System.Text;
命名空间 CDCollection 公开课CD #region 字段 私有只读字符串_artist; 私有只读字符串_album; 私有列表 _track = new List(); #endregion
#region Constructors
public CD()
_artist = "";
_album = "";
_track = null;
public CD(string albumName)
_album = albumName;
public CD(string artistName, string albumName)
_artist = artistName;
_album = albumName;
#endregion
#region Properties
/// <summary>
/// Get/Set Artist Name
/// </summary>
public virtual string Artist
get
return _artist;
set
value = _artist;
/// <summary>
/// Get/Set Album
/// </summary>
public string Album
get
return _album;
set
value = _album;
/// <summary>
/// Get/Set Track Name
/// </summary>
public virtual List<string> Track
get
return _track;
set
value = _track;
#endregion
#region ToString()
/// <summary>
/// Custom ToString() Method
/// </summary>
/// <returns></returns>
public override string ToString()
//Create new StringBuilder object
StringBuilder sb = new StringBuilder();
sb.Append("Artist Name");
//Display error if Artist is not available
if (_artist == null || _artist == "")
sb.Append("\nNo Artist Entered");
else
sb.Append("\n" + this._artist);
sb.Append("\n");
sb.Append("\nAlbum Name");
//Display error if Album is not available
if (_album == null || _album == "")
sb.Append("\nNo Album Entered");
else
sb.Append("\n" + this._album);
sb.Append("\n");
sb.Append("\nTrack Name");
sb.Append("\n");
//Iterate through all tracks stored in list
foreach (string trackName in _track)
//Print each artist
sb.Append("\n" + trackName);
sb.Append("\nEnd of CD Record.........");
return sb.ToString();
#endregion
这是 CompilationCD 类:
using System;
使用 System.Collections.Generic; 使用 System.Linq; 使用 System.Text;
命名空间 CDCollection 公共类 CompilationCD : CD #region 字段
private readonly string _artist;
private readonly string _album;
private List<KeyValuePair<string,string>> _tracks = new List<KeyValuePair<string,string>>();
//List<KeyValuePair> Reference.
//http://msdn.microsoft.com/en-us/library/6sh2ey19(VS.85).aspx
#endregion
#region Constructors
public CompilationCD()
_album = "";
_artist = "Various Artists";
public CompilationCD(string albumName):base(albumName)
_album = albumName;
_artist = "Various Artists";
#endregion
public void AddTracks(string track, string artist)
_tracks.Add(new KeyValuePair<string, string>(track, artist));
#region Properties
public override string Artist
get
return this._artist;
public new List<KeyValuePair<string,string>> Track
get
return _tracks;
set
_tracks = value;
#endregion
#region ToString()
//TEST
public override string ToString()
//Create new StringBuilder object
StringBuilder sb = new StringBuilder();
sb.Append("Artist Name");
//Display error if Artist is not available
if (_artist == null || _artist == "")
sb.Append("\nNo Artist Entered");
else
sb.Append("\n" + this._artist);
sb.Append("\n");
sb.Append("\nAlbum Name");
//Display error if Album is not available
if (base.Album == null || base.Album == "")
sb.Append("\nNo Album Entered");
else
sb.Append("\n" + base.Album);
sb.Append("\n");
sb.Append("\nTrack Name");
sb.Append("\n");
////Iterate through all tracks stored in list
//foreach (string trackName in base.Track)
//
// //Print each artist
// sb.Append("\n" + trackName);
//
for(int i = 0; i <= _tracks.Count; i++)
string track = _tracks[i].Key;
string artist = _tracks[i].Value;
sb.Append("\nTrack");
sb.Append(track);
sb.Append("\nArtist");
sb.Append(artist);
sb.Append("\nEnd of Compilation CD Record.........");
return sb.ToString();
#endregion
我有严格的规则,这意味着我必须从 CD 继承来创建我的 CompilationCD 以及为我的曲目集使用列表>,它需要同时保存曲目和艺术家。我知道疯了=/
此外,我必须将所有类型的 cd 存储在一个类型为 CD (List) 的列表中。
【问题讨论】:
您应该考虑使用运算符is
而不是比较GetType()
的返回值。它更快、更短,并且具有更好的可扩展性(例如,如果您稍后从 CompilationCD
派生一些类)。
【参考方案1】:
为什么不使用字典?它们是键值对的列表,但可以通过键轻松访问。
【讨论】:
在尝试实现字典后,结果发现它有可能损坏太多。 你是什么意思,“打破”?需要详细说明吗? 我的程序是成对设计的,我的合作伙伴已经做了自己的贡献,但在整个应用程序的大部分没有被改变的情况下没有留下太多的改变。 嗯,我认为字典是你最好的选择。您不妨进行重构以清理内容。 好的,如果我将字典存储在 List 中,我将如何通过属性访问 Key 和 Value?【参考方案2】:问题出在您的foreach
循环中。 tempComCols
是 List<CD>
,但 comCD
是 KeyValuePair<string, string>
。因此,您的循环会导致类型转换无效。
很遗憾,由于我们不知道 CD
类(接口?)是什么样的,我无法就其属性提出修复建议。
编辑:以下可能是您方法的更好版本(虽然,我没有正确调试它):
public CompilationCD FindTrackInComCD(string track)
CompilationCD temp = new CompilationCD();
temp = _cdCollection.Where(cd => cd is CompilationCD)
.Cast<CompilationCD>()
.Where(com_cd => com_cd.Tracks.ContainsKey(track))
.FirstOrDefault();
if (temp != null)
return temp;
else throw new ArgumentException("No matches found");
您不能将CompilationCD
转换为KeyValuePair<string, string>
,因此我们直接使用CompilationCD
类。我们可以把搜索曲目列表的责任交给System.Linq
提供的IEnumerable<T>
扩展方法,这样就很容易了。
【讨论】:
我已经为 CD 和 CompilationCD 添加了类 =] 您使用的是哪个版本的 .Net 框架?根据 LINQ 是否可用,“标准”习语会有所不同。【参考方案3】:这是因为 tempComCols
将返回 CD
而不是 KeyValuePair<string, string>
【讨论】:
【参考方案4】:您的List
不包含KeyValuePairs
,因此您不能像它那样循环遍历它。试试这样的:
foreach (CD comCD in tempComCols)
if (comCD.MyKeyValueProp.Key.Contains(track))
return comCD;
但正如 McKay 所说,如果您的 CD
类只封装 KeyValuePair
,则 Dictionary
会容易得多。
【讨论】:
【参考方案5】:tempComCols 是 CD
项目的列表:List<CD> tempComCols ...
,并且您想要迭代 IEnumerable 类型的东西:foreach (KeyValuePair<string, string> comCD in tempComCols)
【讨论】:
【参考方案6】:您正在枚举List<CD>
并分配给KeyValuePair<string, string>
。
您可以像这样在 C# 3 中使用 LINQ 重写您的方法:
public CompilationCD FindTrackInComCD(string track)
return _cdCollection.OfType<CompilationCD>().FirstOrDefault(cd => cd.Name.Contains(track, StringComparison.CurrentCultureIgnoreCase));
顺便说一句,你可以通过写typeof(CompilationCD)
来获得CompilationCD
的System.Type
对象;你不需要打电话给GetType()
。
【讨论】:
【参考方案7】:使用 KeyedCollection http://msdn.microsoft.com/en-us/library/ms132438.aspx
【讨论】:
【参考方案8】:你可以使用:
cd is CompilationCD;
而不是
return cd.GetType() == temp.GetType(); );
如果我理解正确并且 CD 是某种字典,您可以将函数重写为:
public CompilationCD FindTrackInComCD(string track)
return (CompilationCD)_cdCollection.Find(delegate(CD cd)
return (cd is CompilationCD) && (cd.Contains(track)));
【讨论】:
以上是关于从 List<KeyValuePair<string,string>> 返回匹配的主要内容,如果未能解决你的问题,请参考以下文章
将 JSON 反序列化为 List<List<KeyValuePair>> 结果为空
List<KeyValuePair<string,string>> 的语法更好?
数据绑定到每个 KeyValuePair<string, List<T>> 中的最后一个条目
当我尝试使用 List<KeyValuePair<string, string>> 作为参数之一调用成员时,Type.InvokeMember 引发 MissingMethod