如何跳过lambda代码里面的函数?

时间:2010-12-14 23:41:29

标签: c# debugging visual-studio-2010

考虑以下片段:

    [DebuggerStepThrough]
    private A GetA(string b)
    {
        return this.aCollection.FirstOrDefault(a => a.b == b);
    }

如果我使用F11,调试器不会跳过该功能,而是停在 a.b == b

有没有办法跳过这个功能而不是使用F10?

4 个答案:

答案 0 :(得分:4)

IMO这是C#编译器中的一个错误。编译器还应将这些属性放在匿名方法上。解决方法是回退到C#编译器为您完成的手动工作:

[DebuggerStepThrough]
private A GetA(string b)
{
    var helper = new Helper { B = b };

    return this.aCollection.FirstOrDefault(helper.AreBsEqual);
}

private class Helper
{
    public string B;

    [DebuggerStepThrough]
    public bool AreBsEqual(A a) { return a.b == this.B; }
}

但当然这是令人讨厌的,而且非常难以理解。这就是C#编译器应该这样做的原因。但是C#团队的难题当然是:你在方法中放置哪些属性必须复制到内部匿名方法,哪些不应该?

答案 1 :(得分:2)

我可以看到它为什么会发生,但没有办法解决它。也许有人可以建立在此基础之上lambda表达式被编译成匿名方法。

我明白了:Program.GetA.AnonymousMethod__0(测试a)

就像你在你所显示的方法中调用另一个方法一样,按F11将进入该方法。例如/

[DebuggerStepThrough]
static A GetA<A>(IList<A> aCollection, string b) where A : Test
{
    DoNoOp();
    return aCollection.FirstOrDefault(a => a.b == b);
}

static void DoNoOp()
{
    // noop
    Console.WriteLine("got here");
}

答案 2 :(得分:0)

这困扰了我很长一段时间,今天我想出了一种在.NET 4.0中使用表达式树来实现它的方法。

请考虑以下代码:

private class Borked
{
    public object X 
    {
        [DebuggerStepThrough]
        get { throw new NotImplementedException(); }
    }
}

private void SomeMethod()
{
    var bad = new Borked();
    object obj = bad.TryGet(o => o.X);
}

现在 - 我可以调用此代码而不会错过任何一个节拍 - 调试器试图停止的唯一地方是Borked的破坏的getter属性 - 这就是我在那里添加DebuggerStepThrough属性的原因。

我没有接受一个lambda,而是接受一个表达式树(使用相同的语法!!),然后在运行时编译并运行它 - 这是 little 更多的工作(几乎没有) )而不是使用普通的lambda,它不适用于所有东西,但对于简单的Linq查询等,它的效果很好。

所有的魔法都发生在以下方法中 - 同样,最初用于接受常规Func<>参数 - 但是在抛出异常时暂停调试器(尽管有逐步属性),所以我现在用Expression<Func<>>这样做:

[DebuggerStepThrough]
public static T TryGet<OT, T>(this OT obj, params Expression<Func<OT, T>>[] getters)
{
    T ret = default(T);

    if (getters != null)
    {
        foreach (var getter in getters)
        {
            try
            {
                if (getter != null)
                {
                    var getter2 = (Func<OT, T>)getter.Compile();
                    ret = getter2(obj);
                    break;
                }
            }
            catch
            { /* try next getter or return default */ }
        }
    }

    return ret;
}

这是对的 - 你只需调用.Compile()并将返回值转换为可以立即调用的常规Func<>! - 这有多容易?!

在我的实现中,我让用户传入多个参数,以便他们有办法获得回退值(并且只需要创建/评估该回退值 IF )。

另外,我不确定Debug事件被抑制的原因是因为VisualStudio的“Just my Code”,还是因为它在这种方法中以内联方式运行......但是无论哪种方式它都有效,唱吧!!

现在,我猜测在运行时在表达式上调用.Compile方法并不是超快,但实际上,它似乎并没有给我增加任何性能损失。我的疑问。所以,我很兴奋(请原谅多重/多余的刘海和interobang等等。)

答案 3 :(得分:-3)

我不确定这是否有效,但您可以尝试将该属性放在lambda表达式

[DebuggerStepThrough]
private A GetA(string b)
{
    return this.aCollection.FirstOrDefault([DebuggerStepThrough]a => a.b == b);
}