Get the method name that was passed through a lambda expression?

255 views Asked by At

Is it possible to retrieve via Reflection the real method name that was passed through a lambda expression?

I would like to platform invoke some functions with a better error-handling, then to avoid repeating tons of Marshal.GetLastWin32Error conditionals, I thinked in create a generic method to automate that, where I pass a reference object and a lambda expression:

<DebuggerStepThrough>
Private Shared Sub SafePInvoke(Of T)(ByRef resultVar As T, ByVal [function] As Func(Of T))

    resultVar = [function].Invoke

    Dim lastError As Integer = Marshal.GetLastWin32Error

    If lastError <> 0 Then
        Throw New Win32Exception([error]:=lastError, message:=String.Format("Function '{0}' thrown an unhandled Win32 exception with error code '{1}'.",
                                                                            [function].Method.Name, CStr(lastError)))
    End If

End Sub

Then, I can do this to simplify error-handlings:

Dim length As Integer
SafePInvoke(length, Function() NativeMethods.GetWindowTextLength(hWnd))

I don't know if it can be improved more, it would be great to know it.

Well, now, and just for aesthetical things, If the function gets a win32 error I throw an exception and in the exception message I would like to show the real method name, in this case GetWindowTextLength instead of the "anonymous" lambda name.

This is possibly?.

1

There are 1 answers

6
Ňɏssa Pøngjǣrdenlarp On BEST ANSWER

I would not do this. It would be simpler to pass a string var representing the error message you want to display or a portion thereof (like the function name).

The "simplest" way would be to use an Expression Tree. For this, you would need to change the signature of SafePInvoke to accept an Expression.

With that you could compile the expression, and invoke it to execute the PInvoke. If there is an error, work the expression tree to get the name:

Imports System.Linq.Expressions
...
Private Shared Sub SafePInvoke(Of T)(ByRef result As T, expr As Expression(Of Func(Of T)))
    ' compile the function and invoke it
    Dim result = expr.Compile.Invoke()

    Dim lastError As Integer = Marshal.GetLastWin32Error

    If lastError <> 0 Then
        ' this is easy, but it is the full signature w/ params
        'Dim name = expr.Body.ToString

        ' ToDo: add try Catch
        Dim MethName = CType(expr.Body, MethodCallExpression).Method.Name

        Dim errMsg = MethName & " failed"
    End If
End Sub

Casting it to get the name was Sehnsucht's idea, I gave up for the time being.