How to debug Predicates in C#/Visual Studio?
Asked Answered
C

3

10

In debugging mode, if I hover over a predicate, what I see is just some type names and some non-understandable symbols. This makes it very difficult to debug a code, for example to know what predicate some variable is holding. I usually assign this predicates values using lambda expression. Is there any way to have some idea of what the predicates contain?

For example, if I have a Predicate<object> myPred variable or a List<Predicate<object>> predList variables, how can I debug what value myPred has or what predList contains at runtime?

Contract answered 9/6, 2011 at 14:20 Comment(2)
Alternately you could write unit tests to verify the behavior of the code.Cobweb
Given your extra information in your comment to my answer, I believe you need to expand this question or ask a new question re ways to generate 'debuggable' lambda expressions. IMHO the answer to that question is to generate named functions, which, in VB.NET, are readably debuggable.Salina
S
2

[I haven't checked the C# IDE experience, but actually the VS2010 VB.NET experience.]

Either use Expression as @BenVoigt suggests, or don't use anonymous lambdas for your predicates: (VB.NET answer: Use Functions named by you and specify them with the AddressOf operator.)

C# answer is something like: declare explicit functions named by you and specify the function name when assigning the predicate.

Here is my test VB.NET code that confirms at least one way of dynamically creating predicates can be named successfully. In the VB.NET IDE these are easily seen by name.

Module Module1

Sub Main()
    For i = 1 To 2
        'Dim p As Predicate(Of Object) = Function(o) (o Is Nothing)
        'Dim p As Predicate(Of Object) = AddressOf NamedPredicate
        Dim p As Predicate(Of Object) = GeneratePredicate(i)
        Dim q As Expressions.Expression(Of Predicate(Of Object)) = Function(o) (o IsNot Nothing)
        If p(q) Then Console.WriteLine((q.Compile)(p))
    Next
End Sub
Private Function NamedPredicate(ByVal o As Object) As Boolean
    Return (o Is Nothing)
End Function
Private Function GeneratePredicate(ByVal i As Integer) As Predicate(Of Object)

    Dim gp = New Reflection.Emit.DynamicMethod("DynPred" & i, GetType(Boolean), {GetType(Object)})
    Dim mb = gp.GetILGenerator
    mb.Emit(Reflection.Emit.OpCodes.Ldarg, 0)
    mb.Emit(Reflection.Emit.OpCodes.Ldnull)
    mb.Emit(Reflection.Emit.OpCodes.Ceq)
    If i = 2 Then
        mb.Emit(Reflection.Emit.OpCodes.Ldc_I4_0)
        mb.Emit(Reflection.Emit.OpCodes.Ceq)
    End If
    mb.Emit(Reflection.Emit.OpCodes.Ret)
    GeneratePredicate = DirectCast(gp.CreateDelegate(GetType(Predicate(Of Object))), Predicate(Of Object))
End Function
End Module
Salina answered 9/6, 2011 at 18:33 Comment(1)
My program creates a lot of functions programatically, so I don't think this can be doneContract
L
5

You probably want Expression<Predicate<T>>. It can be converted to Predicate<T> in order to call it, but retains the information about the lambda structure.

Lifeguard answered 9/6, 2011 at 15:43 Comment(4)
how can I use it with lambda expression, and what will be shown in the debug?Contract
@Louis: I added an example, let me know if you have further questions.Lifeguard
And this is why you shouldn't put code outside of your answer - the link is broken ...Winona
The code isn't my answer, it is just for further information. All the important keywords and approach are right here on SO.Lifeguard
S
2

[I haven't checked the C# IDE experience, but actually the VS2010 VB.NET experience.]

Either use Expression as @BenVoigt suggests, or don't use anonymous lambdas for your predicates: (VB.NET answer: Use Functions named by you and specify them with the AddressOf operator.)

C# answer is something like: declare explicit functions named by you and specify the function name when assigning the predicate.

Here is my test VB.NET code that confirms at least one way of dynamically creating predicates can be named successfully. In the VB.NET IDE these are easily seen by name.

Module Module1

Sub Main()
    For i = 1 To 2
        'Dim p As Predicate(Of Object) = Function(o) (o Is Nothing)
        'Dim p As Predicate(Of Object) = AddressOf NamedPredicate
        Dim p As Predicate(Of Object) = GeneratePredicate(i)
        Dim q As Expressions.Expression(Of Predicate(Of Object)) = Function(o) (o IsNot Nothing)
        If p(q) Then Console.WriteLine((q.Compile)(p))
    Next
End Sub
Private Function NamedPredicate(ByVal o As Object) As Boolean
    Return (o Is Nothing)
End Function
Private Function GeneratePredicate(ByVal i As Integer) As Predicate(Of Object)

    Dim gp = New Reflection.Emit.DynamicMethod("DynPred" & i, GetType(Boolean), {GetType(Object)})
    Dim mb = gp.GetILGenerator
    mb.Emit(Reflection.Emit.OpCodes.Ldarg, 0)
    mb.Emit(Reflection.Emit.OpCodes.Ldnull)
    mb.Emit(Reflection.Emit.OpCodes.Ceq)
    If i = 2 Then
        mb.Emit(Reflection.Emit.OpCodes.Ldc_I4_0)
        mb.Emit(Reflection.Emit.OpCodes.Ceq)
    End If
    mb.Emit(Reflection.Emit.OpCodes.Ret)
    GeneratePredicate = DirectCast(gp.CreateDelegate(GetType(Predicate(Of Object))), Predicate(Of Object))
End Function
End Module
Salina answered 9/6, 2011 at 18:33 Comment(1)
My program creates a lot of functions programatically, so I don't think this can be doneContract
C
0

if you mean that in such example

new List<int>()
.Select(i => i + 1);

you would like to debug i + 1 part then you can put your mouse cursor (caret) somewhere at i + 1 and press F9 that will add a breakpoint in that expression

Count answered 9/6, 2011 at 14:39 Comment(1)
No, I don't mean that. I edited my question to add clarificationContract

© 2022 - 2024 — McMap. All rights reserved.