If you're like me and use implicit typing, you may have encountered the issue where an implicitly-typed variable needs to be brought out of an inner scope into an outer scope. For example, suppose you are requesting some data from a database and you want to handle any Exceptions. Naturally, you wrap the data in a try...catch call:
try { var theData = GetData(); } catch (Exception ex) { // handle exception } // do something with theData
Now suppose you want to use theData later in the code. How do you reference it? You have to define theData outside of the try..catch, and initialize it to a null value. Since you can't implicit-type a value of null, this requires you to explicitly define the type for the variable. So much for implicit-typed declarations!
There is a clever workaround to this situation by making use of generics and lambda expressions. The compiler is usually able to determine the proper type of any lambda expression if it's a simple return value and method call. Supposing that GetData returns a type of IQueryable<Company>, say, the following lambda expression clearly has a type of Func<IQueryable<Company>>:
() => { try { return GetData(); } catch (Exception ex) { // handle exception return null; } };
Now that we've wrapped the code into a Func, it can be passed into a generic method that does nothing more than call the func and send the return value back to the caller.
T ListScope<T>(Func<T> ScopedFunction) { T result = ScopedFunction(); return result; }
It would seem like this is a pointless process, just to pass a function into another method which calls the passed function. However, since the compiler is able to determine the return type of the inner function, it can also determine the generic type T. Therefore the result can be assigned to an implicitly-typed variable, which no longer has the scoping issue since the entire inner scope was passed in and handled by another method:
var theData = ListScope(() => { try { return GetData(); } catch (Exception ex) { // handle exception return null; } };
Notice that I did not have to define the type anywhere in the above code, and I'm able to pull the value out of the try..catch into variable theData. I've found this method so useful that it is a static utility method in all of my projects. You can also use this for other things besides try..catch, because it's flexible enough to accommodate any scenario:
// if statement var result = LiftScope(() => { if (a == b) return GetData(true); else if (b == c) return GetData(false); else return GetData(true, 2); }); // using statement var result = LiftScope(() => { using (var myContext = new MyDataContext()) { return myContext.MyTable.Where(w => w.A == B).ToList(); } });Happy programming!
No comments:
Post a Comment