We are using LINQ very widely in our system. Particularly LINQ-to-objects. So in some places we end up having a LINQ query in memory build up from some huge expressions. The problem comes when there's some bug in the expressions. So we get NullReferenceException and the stack trace leads us nowhere (to [Lightweight Function]). The exception was thrown inside the dynamic method generated by LINQ.
Is there any easy way to debug such dynamic methods? Or do I have to sacrifice myself to learning WinDBG? :-)
If you are building your own expressions and compiling them, or using AsQueryable, then yes; the LINQ-generated methods will be a royal pain to debug.
You can save some pain by using small fragements of actual methods - at least something useful will show in the stack trace...
Another consideration is: rather than having one huge expression, if you can daisy-chain things a bit more you might have more idea (from the stack trace) where it is failing. The downside is performance - a Where(foo).Where(bar) is two delegate invokes, where-as Where(foo && bar) can be one.
One option might be to swap in a debug version of the extension methods; unfortunately it is a little inconvenient because IQueryable<T>
and Queryable
are in the same namespace... this works, though...
Output first:
>Where: x => ((x % 2) = 0)
<Where: x => ((x % 2) = 0)
>Count
'WindowsFormsApplication2.vshost.exe' (Managed): Loaded 'Anonymously Hosted DynamicMethods Assembly'
<Count
Code:
using System;
using System.Diagnostics;
using System.Linq.Expressions;
namespace Demo
{
using DebugLinq;
static class Program
{
static void Main()
{
var data = System.Linq.Queryable.AsQueryable(new[] { 1, 2, 3, 4, 5 });
data.Where(x => x % 2 == 0).Count();
}
}
}
namespace DebugLinq
{
public static class DebugQueryable
{
public static int Count<T>(this System.Linq.IQueryable<T> source)
{
return Wrap(() => System.Linq.Queryable.Count(source), "Count");
}
public static System.Linq.IQueryable<T> Where<T>(this System.Linq.IQueryable<T> source, Expression<Func<T, bool>> predicate)
{
return Wrap(() => System.Linq.Queryable.Where(source, predicate), "Where: " + predicate);
}
static TResult Wrap<TResult>(Func<TResult> func, string caption)
{
Debug.WriteLine(">" + caption);
try
{
TResult result = func();
Debug.WriteLine("<" + caption);
return result;
}
catch
{
Debug.WriteLine("!" + caption);
throw;
}
}
}
}
If you're using LINQ to Objects, I wouldn't expect to see dynamic methods being created. I'd expect them with LINQ to SQL etc. Could you give an example where you're seeing this?
I don't really have any good debugging tips when it comes to LINQ, but I'm pretty sure MS know about this as a pain point. Could I suggest you try the VS2010 CTP and see if that's better? More for the sake of improving VS than for solving your immediate problem, admittedly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With