Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Debugging .NET dynamic methods

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? :-)

like image 291
Ihar Bury Avatar asked Oct 14 '22 18:10

Ihar Bury


2 Answers

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;
            }
        }
    }
}
like image 75
Marc Gravell Avatar answered Oct 18 '22 14:10

Marc Gravell


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.

like image 41
Jon Skeet Avatar answered Oct 18 '22 12:10

Jon Skeet