Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I convert anonymous type to strong type in LINQ?

Tags:

c#

linq

.net-3.5

I have an array of ListViewItems ( ListViewItem[] ), where I store a SalesOrderMaster object in each ListViewItem.Tag for later reference.

I have some code that right now, goes through each ListViewItem safely casts the .Tag property into a SalesOrderMaster object, then adds that object to a collection of SalesOrders, only after checking to make sure the order doesn't already exist in that collection.

The process to compare sales orders is expensive, and I would like to convert this to a LINQ expression for clarity and performance. ( I also have the Parallel Extensions to .NET Framework 3.5 installed so I can use that to further improve LINQ performance)

So without further ado: This is what I have, and then what I want. ( what I want won't compile, so I know I am doing something wrong, but I hope it illustrates the point )

What I have: ( Slow )

foreach (ListViewItem item in e.Argument as ListViewItem[])
            {
                SalesOrderMaster order = item.Tag as SalesOrderMaster;
                if ( order == null )
                {
                    return;
                }
                if (!All_SalesOrders.Contains(order))
                {
                    All_SalesOrders.Add(order);
                }
            }

What I want: ( Theory )

    List<SalesOrderMaster> orders = 
(from item in (e.Argument as ListViewItem[]).AsParallel() 
select new { ((SalesOrderMaster)item.Tag) }).Distinct();

EDIT: I know the cast is cheap, I said the "Compare", which in this case translates to the .Contains(order) operation

EDIT: Everyone's answer was awesome! I wish I could mark more than one answer, but in the end I have to pick one.

EDIT : This is what I ended up with:

List<SalesOrderMaster> orders = 
(from item in (e.Argument as ListViewItem[]) select (SalesOrderMaster) item.Tag).GroupBy(item => item.Number).Select(x => x.First()).ToList();
like image 848
Russ Avatar asked Apr 29 '09 12:04

Russ


People also ask

Do anonymous types work with LINQ?

You are allowed to use an anonymous type in LINQ. In LINQ, select clause generates anonymous type so that in a query you can include properties that are not defined in the class.

Is LINQ strongly typed?

LINQ query operations are strongly typed in the data source, in the query itself, and in the query execution.

What is anonymous type in LINQ?

Anonymous types typically are used in the select clause of a query expression to return a subset of the properties from each object in the source sequence. For more information about queries, see LINQ in C#. Anonymous types contain one or more public read-only properties.


1 Answers

I see nobody has addressed your need to convert an anonymous type to a named type explicitly, so here goes... By using "select new { }" you are creating an anonymous type, but you don't need to. You can write your query like this:

List<SalesOrderMaster> orders = 
    (from item in (e.Argument as ListViewItem[]).AsParallel() 
    select (SalesOrderMaster)item.Tag)
    .Distinct()
    .ToList();

Notice that the query selects (SalesOrderMaster)item.Tag without new { }, so it doesn't create an anonymous type. Also note I added ToList() since you want a List<SalesOrderMaster>.

This solves your anonymous type problem. However, I agree with Mark and Guffa that using a parallel query here isn't you best option. To use HashSet<SalesOrderMaster> as Guffa suggested, you can do this:

IEnumerable<SalesOrderMaster> query = 
    from item in (ListViewItem[])e.Argument
    select (SalesOrderMaster)item.Tag;

HashSet<SalesOrderMaster> orders = new HashSet<SalesOrderMaster>(query);

(I avoided using var so the returned types are clear in the examples.)

like image 98
Lucas Avatar answered Oct 04 '22 13:10

Lucas