【问题标题】:Get the method name that was passed through a lambda expression?获取通过 lambda 表达式传递的方法名称?
【发布时间】:2015-06-16 20:57:32
【问题描述】:

是否可以通过 Reflection 检索通过 lambda 表达式传递的真实方法名称?

我想用更好的错误处理平台调用一些函数,然后为了避免重复大量 Marshal.GetLastWin32Error 条件,我想创建一个通用方法来自动化它,我传递一个引用对象和一个 lambda 表达式:

<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

然后,我可以这样做来简化错误处理:

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

不知道还能不能再改进,知道就好了。

好吧,现在,只是为了美观,如果函数出现 win32 错误,我会抛出异常,在异常消息中我想显示真实的方法名称,在这种情况下 GetWindowTextLength 而不是“匿名" lambda 名称。

这可能吗?

【问题讨论】:

  • 你可能不喜欢这个结果,你可以求助于表达式树。然而,身体将是 GetWindowTextLength(hWnd) 你可能不想要参数。
  • 从表达式主体我认为可以将其转换为 MethodCallExpression 并将其作为 Method 属性(具有 Name 属性的 MethodInfo 类型)。使用表达式还意味着您必须在方法中编译它才能调用它。
  • 如果对于结果,我们正在谈论接受参数的语法,那么实际上我不喜欢我必须编写的当前语法(lambda 表达式语法的“Function()”关键字)。表达式树会增加和/或会使参数中的写入量变得复杂?我第一次听说表达式树(我已经在 MSDN 中查找了)
  • 它不是*那*糟糕:Sub SafePInvoke(Of T)(ByRef resultVar As T, expr As Expression(Of Func(Of T))) 但这不是你想要的

标签: .net vb.net reflection delegates pinvoke


【解决方案1】:

我不会这样做。传递一个字符串 var 表示您要显示的错误消息或其一部分(如函数名称)会更简单。

“最简单”的方法是使用Expression Tree。为此,您需要更改SafePInvoke 的签名以接受Expression

这样您就可以编译表达式,并调用它来执行 PInvoke。如果有错误,请使用表达式树来获取名称:

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

铸造它来得名是 Sehnsucht 的主意,我暂时放弃了。

【讨论】:

  • 我支持“不会做这部分”;您想要一个名称,只需询问一个(可能比真正的方法名称更清晰)。此外,添加 VB14 后,您将拥有 NameOf 运算符,它可以减少“魔术字符串效果”:SafePInvoke(length, Function() NativeMethods.GetWindowTextLength(hWnd), NameOf(NativeMethods.GetWindowTextLength)) 当然这是一些“重复代码”,但至少重命名可以解决这个问题
  • @Plutonix 再次感谢您,您能解释一下您为什么不这样做吗?仅仅是因为为了美观你会更喜欢传递一个字符串,还是因为在使用表达式时有任何性能问题?。
  • 它很复杂,我不喜欢 expr -> lambda -> Pinvoke 的想法;对我来说太间接了。
  • @ElektroStudios,在this 上给他投票,让他获得积分和铜牌
  • (done) 也许现在有了MethodCallExpression 对象我可以用这个做点什么? stackoverflow.com/questions/30878232/…两位请看,我正在分析整个类MethodCallExpression,尤其是属性属性,但是它有很多属性和成员来学习它的用途。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-03
  • 1970-01-01
相关资源
最近更新 更多