6

What is the proper way to create a variable that will house a list of anonymous objects that are generated through a LINQ query while keeping the variable declaration outside of a try/catch and the assignment being handled inside of a try/catch?

At the moment I'm declaring the variable as IEnumberable<object>, but this causes some issues down the road when I'm trying to use it later...

i.e.

var variableDeclaration;
try{
    ...
    assignment
    ...
}catch...

EDIT:

If it's relevant (don't think it is) the list of objects is being returned as a Json result from an MVC3 action. I'm trying to reduce the time that some using statements are open with the DB as I'm having some performance issues that I'm trying to clear up a bit. In doing some of my testing I came across this issue and can't seem to find info on it.

EDIT 2:

If I could request the avoidance of focusing on LINQ. While LINQ is used the question is more specific to the scoping issues associated with Anonymous objects. Not the fact that LINQ is used (in this case) to generate them.

Also, a couple of answers have mentioned the use of dynamic while this will compile it doesn't allow for the usages that I'm needing later on the method. If what I'm wanting to do isn't possible then at the moment the answer appears to be to create a new class with the definition that I'm needing and to use that.

Jared
  • 5,840
  • 5
  • 49
  • 83
  • 4
    Stand in the bathroom with the lights off and whisper "Jon Skeet" into the mirror 10 times. – Daniel Jan 28 '13 at 01:57
  • @Doc nice... (stinking minimum char count caused this paren statement) – Jared Jan 28 '13 at 02:02
  • If you know the structure of the list of anonymous type, but you aren't ready to fill it, you could generate an empty list of that type beforehand. See [this post](http://stackoverflow.com/questions/1034075/creating-a-list-of-anonymous-type-in-vb) for more info. – Daniel Jan 28 '13 at 02:32

6 Answers6

4

Well, if you're using LINQ, the query is not evaluated unless materialized...

So, you might be able to:

var myQuery = //blah
try
{
    myQuery = myQuery.ToList();  //or other materializing call
}
catch
{
}
spender
  • 117,338
  • 33
  • 229
  • 351
  • The LINQ query is against our DB object that is...custom so at the moment I unfortunately don't believe this is an option. – Jared Jan 28 '13 at 02:08
4

It's possible to get around this by creating a generic Cast method as outlined by Jon Skeet here. It will work and give you the intellisense you want. But, at this point, what's wrong with creating a custom type for your linq method?

public class MyClass
{
    public int MyInt { get; set; }
}

IEnumerable<MyClass> myClass = 
    //Some Linq query that returns a collection of MyClass
Dave Zych
  • 21,581
  • 7
  • 51
  • 66
  • I had actually considered this, but since the objects are being used strictly to return Json I was hoping to avoid this for the simple fact of not having code out there that isn't necessary (granted if this is the only option then it may become necessary). The anonymous object is strictly to return a subset of data from actual objects that exist in the DB...as outlined here http://msdn.microsoft.com/en-us/library/vstudio/bb384105.aspx – Jared Jan 28 '13 at 02:06
  • @spender I actually have R# and am not aware of how to do this. Mind posting? – Jared Jan 28 '13 at 02:14
  • 1
    @Jared, Where you new up your anonymous type, position caret between `new` and `{` and "refactor-this" (ctrl-shift-r) and choose "Replace anonymous type with named class" – spender Jan 28 '13 at 02:19
  • @DaveZych pending some other method besides dynamic it looks like this is the solution that I'll be taking. I've temporarily implemented this as it does solve my problem and was something I was aware of (just hoping to avoid). I'll probably give this another day and then select as answer should nothing else pop up. Thanks! – Jared Jan 28 '13 at 02:27
1

Could you perhaps get away with using dynamic ??

     dynamic variableDeclaration;
     try
     {
         variableDeclaration = SomeList.Where(This => This == That);
     }
     catch { }

Not sure what this will affect further in your code block, but just a thought :)

sa_ddam213
  • 42,848
  • 7
  • 101
  • 110
  • I had tried to use dynamic as the type of object in the list `List` which didn't work. Declaring the variable as simply `dynamic` as you mentioned does compile, but functions the same as declaring a list of `object` so this doesn't gain me anything unfortunately. :( – Jared Jan 28 '13 at 02:12
1

If you are declaring the variable ahead of using it like a try/catch you can't use [var] as it is intendend. Instead you have to type the the variable.

var x = 0;
try{
   x = SomethingReturningAnInt();
}

or

int x;
try{
   x = SomethingReturningAnInt();
}

However in your case you don't really "know" what the method returns

var x = ...;
try{
   x = Something();
}
catch{}

won't work

Option you have when you don't know the type in advance is use of dynamic:

dynamic x;
try{
   x = Something();
}
catch{}

(But that feels like going back to VB4)

lboshuizen
  • 2,746
  • 17
  • 20
  • I had used var in the example code simply to designate a variable declaration...not actually meaning to dictate the use of `var` variable type. I attempted the `dynamic` option as mentioned in another response below, but it behave like declaring the variable as `object` which doesn't help my issue. +1 for examples though. – Jared Jan 28 '13 at 02:17
  • Dynamic does behave like but isn't. It gives you properties that should (but not nesec. are!) exist on the variable, while object doensn't. If you know at least something in advance try using an interface? – lboshuizen Jan 28 '13 at 02:46
1

Another cheat: you can define variable locally (similarly to Jon's hack in Dave Zych answer) and than use it inside try/catch. As long as you can create the same anonymous item type before try-catch you are OK (as anonymous types wit the same field names and types are considered the same):

var myAnonymouslyType = Enumerable.Repeat(
    new {Field1 = (int)1, Field2 = (string)"fake"}, 0);

try 
{ 
   myAnonymouslyType = ...(item => 
     new {Field1 = item.Id, Field2=item.Text})...
}
...

This is safer option than covered in Jon's casting of anonymous types between functions because compiler will immediately find errors if types don't match.

Note: I'd vote for non-anonymous type if you have to go this way...

Note 2: depending on your actual need consider simply returning data from inside try/catch and having second return of default information outside.

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
1

This has vexed me for a while. In the end I've build some Generic helper methods where I can pass in the code that generates the anonymous objects, and the catch code as lamdas as follows

public static class TryCatch
{
    public static T Expression<T>(Func<T> lamda, Action<Exception> onException)
    {
        try
        {
            return lamda();
        }
        catch(Exception e)
        {
            onException(e);
            return default(T);
        }            
    }

}

//and example

Exception throwexception = null;
        var results = TryCatch.Expression(
            //TRY
            () => 
                {
                    //simulate exception happening sometimes.
                    if (new Random().Next(3) == 2)
                    {
                        throw new Exception("test this");
                    }
                    //return an anonymous object
                    return new { a = 1, b = 2 };
                } ,
            //CATCH
            (e) => { throwexception = e;                         
                     //retrow if you wish
                     //throw e;
                   }
            );

https://gist.github.com/klumsy/6287279

klumsy
  • 4,081
  • 5
  • 32
  • 42