How to use ToList() to print multiple list items?

Viewed 567

While trying to print items in a list after selecting fields from that list, I get an error saying "cannot convert from list to item". Some queries work, but a few, like the one listed below, require a different print void. I'd like it to work without multiple print voids.

I have tried placing the foreach loop directly under the query, but it can't locate the proper items to print.

 List<Item> items = new List<Item>();//create list

 items.Add(new Item()
            {

                ItemGroup = "Electric",
                ItemDescription = "Electric Sander",
                Quantity = 7,
                UnitPrice = 59.98f,
            });//add list item

 var totalValue = items
            .Select(x => (
                x.ItemDescription,
                x.Quantity,
                x.UnitPrice,
                x.Price = TotalValue((int)x.Quantity, (float)x.UnitPrice)
                ))
            .OrderBy(x => x.Quantity)
            .ToList();//create new list for question 1

         PrintItems(totalValue);//print item (throwing error "can't 
 //convert list to item"

  static void PrintItems(List<Item> items)//print void
    {
        foreach (var Item in items)
        {
            Console.WriteLine("" + Item);
        }
    }
4 Answers

You are using C# 7 feature to create tuple using LINQ Select, meaning you no longer have your List<Item> type, but List<yourTupleType>.

If that's all you are going to calculate in your Select, then why not just move TotalValue to Item class

public class Item
{
    public string ItemGroup { get; set; }
    public string ItemDescription { get; set; }
    public int Quantity { get; set; }
    public float UnitPrice { get; set; }

    public float Price
    {
        get
        {
            // your TotalValue logic since you already have quantity and unit Price
            // something like
            return Quantity * UnitPrice;
        }
    }
}

then you can just order your collection and pass to PrintItems method.

Another option if you want to have TotalValue method outside Item class - don't create new object but just recalculate price for each item.

items.ForEach(i => i.Price = TotalValue((int)x.Quantity, (float)x.UnitPrice));
PrintItems(items.OrderBy(i => i.Quantity).ToList());

What your Select() statement returns is a Tuple. And a Tuple cannot be converted to an Item

In C#, when you write (1, "hello", 1.0f), you are creating a tuple of type ValueTuple<int, string, float> or in short (int, string, float), and it cannot be used interchangeably with a class like

class NotTuple
{
    public int PropInt { get; set; }
    public string PropString { get; set; }
    public float PropFloat { get; set; }
}

(Because they have different type!)

Therefore, when you do

.Select(x => (
       x.ItemDescription,
       x.Quantity,
       x.UnitPrice,
       x.Price = TotalValue((int)x.Quantity, (float)x.UnitPrice)
    ))

you create an IEnumerable<(string, int, float, float)>, not a IEnumerable<Item>. Later when you call .ToList(), the IEnumerable is consumed and materialized to a List<(string, int, float, float)>, which is not interchangeable with List<Item>.

Can you Skip the PrintItems method? if you can... do this

        List<Item> items = new List<Item>();//create list

    items.Add(new Item()
        {

            ItemGroup = "Electric",
            ItemDescription = "Electric Sander",
            Quantity = 7,
            UnitPrice = 59.98f,
        });//add list item

         var totalValue = items.GroupBy(a => new { a.Quantity, a.ItemDescription, a.UnitPrice })
                  .Select(g => new { g.Key.ItemDescription, g.Key.Quantity, g.Key.UnitPrice,
                                     Price = g.Sum(s => (int)g.Key.Quantity * (float)g.Key.UnitPrice)
                                     });

    foreach (var Item in totalValue)
    {
        Console.WriteLine("" + Item);
    }
Related