无法将源类型转换为目标类型List<KeyValuePair> Linq

4
我有一个方法是返回一个列表>>,但我遇到了一个错误:
无法将源类型System.Collections.Generic.List<{Key:int,Value:string}>转换为目标类型System.Collections.Generic.KeyValuePair<'int,string'> 我正在尝试将Linq选择语句变成一个新的列表,但我不明白初始化列表是否有问题,或者是如何在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();
        }
    }
3个回答

5
当你写new { s.Key, s.Value }时,你正在实例化一个具有属性KeyValue的新匿名类型。相反,你可能想使用KeyValuePair的构造函数,写成new KeyValuePair(s.Key, s.Value)
另外,请注意,你的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查询时特别有用。当您的程序编译时,会发出一个新的匿名类型,其中包含2个名为KeyValue的属性。您可以将其视为一个新类,没有名称,并且仅有2个属性(完整类和匿名类型之间还有其他差异,但这是一种方便思考的方式)。您的方法应返回一个KeyValuePairs列表,但您提供了一个由这种新类型对象组成的列表。请在此处阅读更多相关信息:here
作为一般的小提示,您不需要声明tp变量。而是可以在switch语句中使用return语句:

2
他的返回类型是List,所以需要使用ToList。顺便说一下。 - Justin Pihony
我之前不知道可以完全省略选择部分,但这确实使它更高效、易读。谢谢Ben、Sergey和Justin! - Elaine K

4

正如其他人已经指出的那样,您在Select中创建了一个新的匿名类型,而不是KeyValuePair。但是,您已经使用KeyValuePair在工作,因此甚至不需要Select

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

Select中重新实例化对象确实没有意义(除非你想要一个新的引用...但在这种情况下,KVP是不可变的)。 Where.ToList 更具表现力,因为它更容易理解,至少我个人认为是这样。


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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接