【问题标题】:Debugging .NET dynamic methods调试 .NET 动态方法
【发布时间】:2008-10-29 08:21:50
【问题描述】:

我们在我们的系统中非常广泛地使用 LINQ。特别是 LINQ-to-objects。因此,在某些地方,我们最终会在内存中使用一些巨大的表达式构建 LINQ 查询。当表达式中有一些错误时,问题就来了。所以我们得到 NullReferenceException 并且堆栈跟踪导致我们无处可去(到 [轻量级函数])。异常是在 LINQ 生成的动态方法中引发的。

有没有简单的方法来调试这种动态方法?还是我必须牺牲自己来学习 WinDBG? :-)

【问题讨论】:

  • Linq to objects 通常指 System.Linq.Enumerable 的方法。这些不涉及动态方法(但可以涉及匿名方法)。你真的在使用动态方法吗?
  • @David - 我也问过同样的问题; Orlangur 正在使用 AsQueryable 来使用具有多个源的相同代码 - 因此需要动态方法。

标签: c# .net linq debugging dynamic-method


【解决方案1】:

如果您正在构建自己的表达式并编译它们,或者使用 AsQueryable,那么可以; LINQ 生成的方法调试起来非常痛苦。

您可以通过使用实际方法的小片段来节省一些痛苦 - 至少有用的东西会显示在堆栈跟踪中......

另一个考虑因素是:与其拥有一个巨大的表达式,不如通过菊花链更多的东西,你可能会(从堆栈跟踪)知道它失败的地方。缺点是性能 - Where(foo).Where(bar) 是两个委托调用,where-as Where(foo && bar) 可以是一个。

一种选择可能是换入扩展方法的调试版本;不幸的是,这有点不方便,因为 IQueryable<T>Queryable 在同一个命名空间中......不过这可行......

先输出:

>Where: x => ((x % 2) = 0)
<Where: x => ((x % 2) = 0)
>Count
'WindowsFormsApplication2.vshost.exe' (Managed): Loaded 'Anonymously Hosted DynamicMethods Assembly'
<Count

代码:

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;
            }
        }
    }
}

【讨论】:

  • 不幸的是,在我们的例子中,实际方法不是一个选项,因为构建表达式的代码也与其他 LINQ 提供程序一起使用,因此它必须与 IQueryable 一起使用
  • 好吧,我想我可以创建自己的 LINQ-to-objects 提供程序,专门用于调试,它将逐步递归地评估所有表达式,并将可查询的方法调用替换为可枚举的方法调用。那应该可以解决问题。然而,这本身并不是一件容易的事。
  • 确实如此。抱歉,我想不出更好的办法,除了在单元测试时手动将你的表达式分解成小块......并不总是那么容易。
【解决方案2】:

如果您使用的是 LINQ to Objects,我不希望看到创建动态方法。我希望他们使用 LINQ to SQL 等。你能举个例子吗?

对于 LINQ,我真的没有任何好的调试技巧,但我很确定 MS 知道这是一个痛点。我可以建议你试试VS2010 CTP 看看是否更好?诚然,更多是为了改进 VS,而不是为了解决眼前的问题。

【讨论】:

  • 通过 LINQ to Objects 我的意思是通过 AsQueryable() 使用内存中的集合
  • 那么为什么是 AsQueryable? 一般 IEnumerable 更简单,这意味着可以直接使用简单的 lambda。您仍然可以 .Compile() 您手动构建的 lambdas 来使用它们...
  • 乔恩,你能更新链接吗,我想查看链接,但它不再起作用了。谢谢
  • @cpoDesign:好吧,将近四年后,我们几乎发布了 VS2012,而 VS2010 已经存在了很长时间......实际上,这个答案不再有用,我当我给你一点时间来检查这条评论时,我会删除它。
  • 无需删除,只是好奇地阅读了您的建议。帕夫
【解决方案3】:

查看debug visualizer 了解最初由Haibo Luo 开发并由Roy Osherove 进一步开发的动态方法

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-20
    相关资源
    最近更新 更多