views:

38

answers:

2

I'm new to Linq to Objects, and I've just hit the problem of anonymous types and scope.

For example, this works just fine:

    Public Sub CreateResults()
        results = From e In CustomerList
                  Join f In OrderList On CustomerList.ID Equals OrderList.ID
                  Select New With {e.FirstName, e.LastName, f.OrderID}

        For Each r in results
            Console.Writeline(r.FirstName, r.LastName, r.OrderID)
        Next t
    End Sub

This however does not:

Public Class Foo

    Private _linqResults 

    Public Sub CreateResults()
        _linqResults = From e In CustomerList
                       Join f In OrderList On CustomerList.ID Equals OrderList.ID
                       Select New With {e.FirstName, e.LastName, f.OrderID}
    End Sub

    Public Sub PrintResults()
        For Each r in _linqResults
            Console.Writeline(r.FirstName, r.LastName, r.OrderID)
        Next t
    End Sub

End Class

I've been looking through SO and other places trying to find a simple solution to this without much luck. Is there any way to access the fields of an anonymous type outside the scope of the method containing the Linq query? Something like:

Console.Writeline(r("FirstName").ToString, r("LastName").ToString)

would be acceptable, though not ideal.

I really, really don't want to start creating additional classes/structures/DTOs to handle what are supposed to be dynamic queries.

+1  A: 

It is not possible to infer the types the way you want. You have a few choices though:

  1. Make a additional class (which you don't want)

  2. Change the style of the class so CreateResults and PrintResults is in the same method as you have done. BUT you properly have a good reason not to do that.

  3. Use the dynamic type (I guess there is one in VB, but I don't know for sure. I'm a C# man) and then you simple access the properties you want as you do in your example. This is obviously not as fast as static typing.
  4. There is a hack to do it (at least in C#). But it is not pretty. See http://stackoverflow.com/questions/3149209/how-to-return-anonymous-type-while-using-linq
  5. Instead of using a custom class you could use the tuple classes. System.Tuple and store the data there. They came in .Net 4 I think.

In the end I really think a custom class is the way to go unless you have a good reason not to. I would also like a way to do the same thing you want to, but a custom class can be described in a few lines with newer syntax.

EDIT: Added a few points and changed a little bit

Example with dynamic in C# as requested

class Foo
{
    private dynamic _linqResults;

    public void CreateResults()
    {
        var someData = Enumerable.Range(1, 10);

        _linqResults = from i in someData
                       select new
                       {
                           Number = i
                       };
    }

    public void PrintResults()
    {
        foreach (var i in _linqResults)
            Console.WriteLine(i.Number);
    }
}

As you maybe see, it is almost the same syntax as you want. It just uses dynamic which is a bit slower - but it sounds like that you already uses or will use some kind of dynamic/reflection in datagrid and csv. It of cause depends on which DataGrid and CSV (your own?) you use.

As mentioned in another answer, the compiler can't infer the types and IntelliSense will not be your guide in PrintResults.

Little update VB has a similar syntax which you can find a good walk-trough with here: http://blogs.msdn.com/b/vbteam/archive/2008/12/17/walkthrough-dynamic-programming-in-visual-basic-10-0-and-c-4-0-lisa-feigenbaum.aspx

lasseespeholt
Thanks lasseespeholt. As my query results are going to a datagrid, a csv file and a report as well, I guess additional classes are the least worst option.
matt
Okay thanks :) But many CSV generators and datagrids actually uses reflection to write out properties so the dynamic method would not necessarily be all bad in this case. But it depends on your datagrid and CSV generator.
lasseespeholt
Would you be able to point me to any examples of using the dynamic method? C# examples are fine. Thanks.
matt
There you go :)
lasseespeholt
Many thanks lasseespeholt!
matt
+1  A: 

Here's the deal.

You're creating an anonymous type. The compiler only "knows" about the anonymous type within the scope in which it is created.

In the second example, you are attempting to store that anonymous type outside of the scope of its creation. You can do this, but since the type is anonymous you lose the ability to access the compiler-generated properties except via reflection.

Long story short, if you wish to store the results of a linq query outside of the scope it is created, you must create a type to hold those results.

Will