Satya
Satya

Reputation: 45

Cannot convert Systems.Collections.GenericList<T> to T

I have dictionary with value being a list. I need to read each of the list's to extract a field. But getting the following error at the foreach loop

cannot convert type System.Collections.Generic.List<UserQuery.Employee> to UserQuery.Employee

It works if I use the firstorDefault as in the commented line for var iValue. But I will have multiple records to check in the dictionary that I am reading(though in this example, I hard coded 1, to test my code).

void Main()
{
    var svalue =1;
    List<Employee> emplist = new List<Employee>()
    {
         new Employee{ EID=10, Ename="John"},
         new Employee{ EID=11, Ename="Adam"},
         new Employee{ EID=12, Ename="Ram"}
    };
    List<Employee> emplist1 = new List<Employee>()
    {
         new Employee{ EID=1, Ename="Jo"},
         new Employee{ EID=1, Ename="Ad"},
         new Employee{ EID=1, Ename="Ra"}
    };

    var dict1 = new Dictionary<int, List<Employee>>();
    dict1.Add(1, emplist);
    dict1.Add(2, emplist1);

    //var ivalue = dict1.FirstOrDefault(x => x.Key == svalue).Value.ToList();
    var ivalue = dict1.Where(kvp => dict1.ContainsKey(1)).Select(x => x.Value);

    Console.WriteLine(ivalue);
    foreach (Employee emp in ivalue)
    {
        Console.WriteLine(emp.EID);
    }
}

class Employee
{
    public int EID { get; set;}
    public string Ename {get; set;}
}

Upvotes: 1

Views: 306

Answers (6)

Dmitrii Bychenko
Dmitrii Bychenko

Reputation: 186668

Your current code

 var ivalue = dict1
   .Where(kvp => dict1.ContainsKey(1)) //TODO: Very strange condition: check it
   .Select(x => x.Value);

returns IEnumerable<List<Employee>> as a result (ivalue). Since you want IEnumerable<Employee> only, you have to flatten the result:

 var ivalue = dict1
   .Where(kvp => dict1.ContainsKey(1))
   .SelectMany(kvp => kvp.Value); // kvp: we still have key-value pair

However, it's not the way we deal with dictionaries; you're, probably, looking for something like this (let's preserve some Linq: - .Select(emp => emp.EID)):

 if (dict1.TryGetValue(1, out var ivalue)) // do we have corresponding value?
   Console.WriteLine(String.Join(Environment.NewLine, ivalue // if yes, print them out
     .Select(emp => emp.EID)));

Upvotes: 2

Camilo Terevinto
Camilo Terevinto

Reputation: 32058

That's not how you normally work with a Dictionary. What you want to do is something like this:

if (dict1.ContainsKey(1)) // if the dictionary contains the key
{
    var ivalue = dict1[1]; // get the value of that key
}

With this, you are using the most effective way to search the dictionary. So you should do this instead:

var dict1 = new Dictionary<int, List<Employee>>();
dict1.Add(1, emplist);
dict1.Add(2, emplist1);

if (dict1.ContainsKey(1))
{
    var ivalue = dict1[1];

    Console.WriteLine(ivalue); // this will print System.Collections.Generic.List<Employee>
    foreach (Employee emp in ivalue)
    {
        Console.WriteLine(emp.EID);
    }
}

Another option is to use TryGetValue:

var dict1 = new Dictionary<int, List<Employee>>();
dict1.Add(1, emplist);
dict1.Add(2, emplist1);
List<Employee> ivalue = null;
if (dict1.TryGetValue(1, out ivalue))
{
    Console.WriteLine(ivalue); // this will print System.Collections.Generic.List<Employee>
    foreach (Employee emp in ivalue)
    {
        Console.WriteLine(emp.EID);
    }
}

Upvotes: 1

Steve
Steve

Reputation: 216243

The Where receives two times the KeyValuePair and of course returns true for both KeyValuePair because you ask always the same question. Does the dictionary contains the Key == 1? Yes. So the return from the Where is an enumerable of two List<Employee> elements that cannot be converted to a single generic list.

var ivalue = dict1.FirstOrDefault(kvp => dict1.ContainsKey(1));
if(ivalue.Value != null)
    foreach (Employee emp in ivalue.Value)
       Console.WriteLine(emp.EID);

Of course, as pointed in comments, this use of Linq is unwarranted because your code could simplified with just

List<Employee> empList;
// Try directly to get the List<Employee> that match the Key
// if found you have the empList initialized with the matching list
// otherwise TryGetValue returns false.
if(dict.TryGetValue(1, out empList))
    foreach (Employee emp in empList)
       Console.WriteLine(emp.EID);

Upvotes: 0

Royi Namir
Royi Namir

Reputation: 148514

I don't think you've meant : dict1.ContainsKey(1))

I think you're after this :

var ivalue = dict1.FirstOrDefault(d =>d.Key==1 ).Value ;


if (ivalue!=null)
foreach (Employee emp in ivalue)
{
    Console.WriteLine(emp.EID);
}

Notice that this :

var ivalue = dict1.Where(kvp => dict1.ContainsKey(1)).Select(x => x.Value);

checks if dictionary has 1 as key , but doesn't consider that key in results.

Upvotes: 0

Johan Donne
Johan Donne

Reputation: 3285

var ivalue = dict1.Where(kvp => dict1.ContainsKey(1)).Select(x => x.Value);

will return an 'IEnumerable' with elements of type List. so you would need two nested foreach loops:

the 'outer' one to iterate through all the lists retrieved from the Dictionary, the 'inner' one to iterate through all the employees in the current List.

Upvotes: 0

Haytam
Haytam

Reputation: 4733

When you do var ivalue = dict1.Where(kvp => dict1.ContainsKey(1)).Select(x => x.Value); You're filtering your list with the Where method and then selecting all the values with Select.

It's normal that you get that exception, because Select gives you a list, not a single entry. You should either foreach that list, or use FirstOrDefault and get 1 single value.

foreach (var value in dict1.Where(kvp => dict1.ContainsKey(1)).Select(x => x.Value))
{
    // ...
}

Or

var ivalue = dict1.Where(kvp => dict1.ContainsKey(1)).Select(x => x.Value).FirstOrDefault();

Upvotes: 0

Related Questions