I have a method that is a List<KeyValuePair<int,string>>
that returns a list; however, I'm getting an error:
Cannot convert source type
System.Collections.Generic.List<{Key:int, Value:string}>
to target typeSystem.Collections.Generic.KeyValuePair<'int,string'>>
.
I am trying to make a Linq select statement into a new list but I don't understand if the initialized list is the problem or if its how I'm getting the values in the Linq statement.
Here is the method:
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;
}
Here's the method that fills the list:
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();
}
}
When you write new { s.Key, s.Value }
you are instantiating a new anonymous type with properties Key
and Value
. Instead, you probably meant to use the contructor of KeyValuePair
by writing new KeyValuePair(s.Key, s.Value)
.
Note, too, that your Where
clause is already filtering a list of KeyValuePairs
, and so no projection is even necessary. In other words, you can drop the entire Select
statement in this case.
So, you could use the KeyValuePair
constructor and write:
tp = st.Where(s => s.Key == (int)Status.Open || s.Key == (int)Status.Reviewed)
.Select(kvp => new KeyValuePair(kvp.Key, kvp.Value)).ToList();
Or, even better, simply drop the Select
statement:
tp = st.Where(s => s.Key == (int)Status.Open || s.Key == (int)Status.Reviewed).ToList();
A little bit more on anonymous types: Anonymous types are a C# features that allow you to make quick ad-hoc classes with custom properties. They are especially useful with Linq
queries. When your program compiles, a new anonymous type is emitted with 2 properties named Key
and Value
. You can thing of this a new class, without a name, that has exactly 2 properties (there are some other differences between full-fledged classes and anonymous types, but this is a convenient way to think about it). Your method is expected to return a list of KeyValuePairs
, but you have provided a list of objects of this new type. Read more about them here.
As a general minor note, you do not need to declare the tp
variable at all. Instead you can return
within your switch
statement:
As others have already pointed out, you are creating a new anonymous type in your Select
, not a KeyValuePair
. However, you are already working against a KeyValuePair
, so you do not even need the Select
tp = st.Where(...where...).ToList();
There is really no point to re-instantiating the objects in the Select
(unless you want a new reference...but KVP is immutable in this case). The Where.ToList
is more expressive simply because it is less to grok, at least IMHO
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With