2014-01-14 73 views
4

我有一个方法是返回一个列表的List<KeyValuePair<int,string>>;然而,我发现了一个错误:无法将源类型转换为目标类型List <KeyValuePair> Linq

Cannot convert source type System.Collections.Generic.List<{Key:int, Value:string}> to target type System.Collections.Generic.KeyValuePair<'int,string'>> .

我试图做一个LINQ的select语句到一个新的列表,但我不明白,如果初始化列表是问题,或者它如何我越来越Linq语句中的值。

这里是方法:

public static List<KeyValuePair<int,string>> GetStatus(int status) 
{ 
    List<KeyValuePair<int,string>> st = SelectList.GetStatuses(); 
    List<KeyValuePair<int,string>> tp; 

    switch(status) 
    { 
     case (int)Status.Completed: 
      tp = st.Where(s => s.Key == (int)Status.Completed || 
          s.Key == (int)Status.NotValid) 
       .Select(s => new { s.Key, s.Value }).ToList(); 
     case (int)Status.Open: 
      tp = st.Where(s => s.Key == (int)Status.Open || 
          s.Key == (int)Status.Reviewed) 
       .Select(s => new { s.Key, s.Value }).ToList(); 
     default: 
      break; 
    } 
    return tp; 
} 

下面是填充列表的方法:

public static List<KeyValuePair<int, string>> GetStatuses() 
    { 
     using (var con = new SqlConnection()) 
     { 
      var sql = @"SELECT ID [Key], Text [Value] from Statuses"; 

      return (con.Query<KeyValuePair<int, string>>(sql.ToString(), commandType: commandType:Text) ?? Enumerable.Empty<KeyValuePair<int, string>>()).ToList(); 
     } 
    } 

回答

5

当你写new { s.Key, s.Value }你实例化一个新的匿名类型与性质KeyValue。相反,您可能打算通过编写new KeyValuePair(s.Key, s.Value)来使用KeyValuePair的构造函数。

也请注意,您的Where子句已经过滤了KeyValuePairs的列表,因此不需要进行任何投影。换句话说,在这种情况下,您可以删除整个Select声明。

所以,你可以使用KeyValuePair构造函数和写:

tp = st.Where(s => s.Key == (int)Status.Open || s.Key == (int)Status.Reviewed) 
     .Select(kvp => new KeyValuePair(kvp.Key, kvp.Value)).ToList(); 

,或者甚至更好,简单地丢弃Select声明:

tp = st.Where(s => s.Key == (int)Status.Open || s.Key == (int)Status.Reviewed).ToList(); 

多一点点的匿名类型:匿名类型是一种C#功能,可让您使用自定义属性创建快速临时类。它们对Linq查询尤其有用。当您的程序编译时,会发出一个新的匿名类型,其中包含名为KeyValue的两个属性。你可以看到这个新类没有名字,只有2个属性(全类和匿名类之间还有一些不同之处,但这是考虑它的一种便利方式)。您的方法预计会返回KeyValuePairs的列表,但您已提供了此新类型的对象列表。详细了解它们here

作为一般的小调,你根本不需要声明tp变量。相反,您可以在switch声明中输入return

+2

他的返回类型是一个列表,所以ToList是必要的btw –

+0

@JustinPihony谢谢,编辑。 –

+0

我不知道我可以完全删除选择部分,但这当然确实使它有效且易于阅读。谢谢Ben,Sergey,Justin! –

2

不能将匿名对象列表{ Key, Value }分配给类型为KeyValuePair<int,string>的变量。如果您想重复使用与GetStatuses()返回的相同KeyValuePair实例,则只需删除Select投影。否则,项目中的每个键值对KeyValuePair<int,string>类型的新实例(下文取消注释行):

switch(status) 
{ 
    case (int)Status.Completed: 
     tp = st.Where(s => s.Key == (int)Status.Completed || s.Key == (int)Status.NotValid) 
       //.Select(s => new KeyValuePair<int, string>(s.Key, s.Value)) 
       .ToList(); 
     break; // also make sure you have break here 
    case (int)Status.Open: 
      tp = st.Where(s => s.Key == (int)Status.Open || s.Key == (int)Status.Reviewed) 
       //.Select(s => new KeyValuePair<int, string>(s.Key, s.Value)) 
       .ToList(); 
     break; 
} 
4

正如其他人已经指出的那样,你在你的Select,不是KeyValuePair创建一个新的匿名类型。但是,你已经工作了针对KeyValuePair,所以你甚至都不需要Select

tp = st.Where(...where...).ToList(); 

实在是没有点重新实例在Select的对象(除非你想有一个新的参考...但在这种情况下KVP是不可变的)。 Where.ToList更具表现力,因为它少了groh,至少恕我直言

相关问题