【问题标题】:How do I determine the type of a class in a function definition?如何确定函数定义中类的类型?
【发布时间】:2025-12-13 01:50:02
【问题描述】:

我不太确定如何问这个问题,但基本上我想知道如何指定一个类类型,以便我可以键入和粘贴代码。

例如我有以下代码:

Public Class CustInfo
    Implements INotifyPropertyChanged

    Public Event PropertyChanged(sender As Object, e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

    Protected Sub NotifyPropertyChanged(ByVal Name As String)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(Name))
    End Sub

    Protected Sub NotifyPropertyChanged()
        Dim myStackFrame As New StackFrame(1)
        Dim myChangingPropertyName As String = myStackFrame.GetMethod.Name.Split("_")(1)
        NotifyPropertyChanged(myChangingPropertyName)
    End Sub

    Protected Sub NotifyPropertyChanged(Of TResult)(propertyExpr As Expression(Of Func(Of CustInfo, TResult)))
        NotifyPropertyChanged(Me.GetPropertySymbol(propertyExpr))
    End Sub

这个想法是让最后一个Sub 是通用的,也就是说,不必在它的定义中特别指定CustInfo。这样我就可以将这段代码复制到任何其他类中,并且它不会被修改。

我尝试创建一个返回类类型的属性并使用它,但可以预见的是失败了。我尝试使用 TypeOf,Me,甚至是“this”,但没有任何效果。似乎必须有一种方法让编译器根据我将最后一个子更改为时收到的此错误消息来了解这一点:

Protected Sub NotifyPropertyChanged(Of TResult)(propertyExpr As Expression(Of Func(Of TResult)))
    NotifyPropertyChanged(Me.GetPropertySymbol(propertyExpr))
End Sub

Data type(s) of the type parameter(s) in extension method 'Public Function GetPropertySymbol(Of TResult)(expr As System.Linq.Expressions.Expression(Of System.Func(Of CustInfo, TResult))) As String' defined in 'CustClasses.Extensions' cannot be inferred from these arguments. Specifying the data type(s) explicitly might correct this error.

所指的扩展方法是:

<Extension()>
Public Function GetPropertySymbol(Of T, TResult)(obj As T, expr As Expression(Of Func(Of T, TResult))) As String
    Return DirectCast(expr.Body, MemberExpression).Member.Name
End Function

因此,您可以看到编译器正确推断出正在发生的事情,但仍然无法使用它。唯一看似未知的类型是 TResult,但应该可以根据扩展方法中已知的其他信息轻松推断出该类型。

在过程定义中一般性地指定类类型可能是不可能的,在这种情况下,我会在每次使用它时修改代码,但我宁愿不这样做,并在过程中学习一些新的东西。

【问题讨论】:

  • 请注意,正如您当前声明的那样,propertyExpr 需要为 As Expression(Of Func(Of &lt;type of Me&gt;, TResult)) 以匹配 expr。 (我现在已经充分审查了您的问题,以一般的方式知道这是您要解决的问题。)

标签: vb.net linq linq-expressions


【解决方案1】:

编辑: 不按说明工作。您仍然需要指定 T As 以允许它调用 .NotifyPropertyChanged。你能为此定义一个接口吗?


您可以将NotifyPropertyChanged(Of TResult)“降级”为Shared 方法并提供Me,从而允许在调用它的位置隐含其类型:

Shared Protected Sub NotifyPropertyChanged(Of T, TResult)(This As T, propertyExpr As Expression(Of Func(Of T, TResult)))
    This.NotifyPropertyChanged(This.GetPropertySymbol(propertyExpr))
End Sub

现在调用是

NotifyPropertyChanged(Me, myChangingPropertyName)

(未经测试 - 但无论如何都不起作用 :-( )

【讨论】:

  • 我正在为此定义一个界面,因为我认为您可能正在做某事,但到目前为止我还没有成功。
【解决方案2】:

根据@Mark Hurd 的回答,我想出了一些可以让使用属性变得更加容易的方法。我决定创建一个用MustInherit 装饰的类,它实现INotifyPropertyChanged 并包括所有需要的NotifyPropertyChanged 代码,所有这些代码都使用泛型设置,以实现最大程度的重用和可移植性。我很想听听有关此解决方案的一些反馈。我没有发现任何问题,但我很容易遗漏一些东西。

Public MustInherit Class AutomaticNotfiyPropertyChanged
    Implements INotifyPropertyChanged

    Public Event PropertyChanged(sender As Object, e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

    Protected Sub NotifyPropertyChanged(ByVal Name As String)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(Name))
    End Sub

    Protected Sub NotifyPropertyChanged()
        Dim myStackFrame As New StackFrame(1)
        Dim myChangingPropertyName As String = myStackFrame.GetMethod.Name.Split("_")(1)
        NotifyPropertyChanged(myChangingPropertyName)
    End Sub

    Protected Shared Sub NotifyPropertyChanged(This As AutomaticNotfiyPropertyChanged, Name As String)
        This.NotifyPropertyChanged(Name)
    End Sub

    Protected Overridable Sub NotifyPropertyChanged(Of TResult)(propertyExpr As Expression(Of Func(Of AutomaticNotfiyPropertyChanged, TResult)))
        NotifyPropertyChanged(GetPropertySymbol(propertyExpr))
    End Sub

    Protected Shared Sub NotifyPropertyChanged(Of T, TResult)(This As T, propertyExpr As Expression(Of Func(Of T, TResult)))
        Dim myParent As AutomaticNotfiyPropertyChanged = TryCast(This, AutomaticNotfiyPropertyChanged)

        If myParent IsNot Nothing Then
            AutomaticNotfiyPropertyChanged.NotifyPropertyChanged(DirectCast(myParent, AutomaticNotfiyPropertyChanged), This.GetPropertySymbol(propertyExpr))
        End If
    End Sub

End Class

然后,通知其他属性更改的调用将是NotifyPropertyChanged(Me, Function(x) x.myChangingProperty),或者如果您想通知当前属性正在更改,则需要调用NotifyPropertyChanged()。此外,NotifyPropertyChanged(Me, "myChaningProperty")NotifyPropertyChanged("myChangingProperty") 也可以使用。最后,如果 NotifyPropertyChanged(Of TResult) 被覆盖以包含派生类,那么像 NotifyPropertyChanged(Function(x) x.myChaningProperty) 这样的调用也将起作用。

另外,我发现NotifyPropertyChanged(Me, Function(x) x.myChaningProperty) 可以正常工作,并且会被编译器检查。但是,IntelliSense 不适用于x。我觉得这很奇怪,因为编译器清楚地知道x 是什么,因为它甚至可以更正变量的大小写。它不会破坏交易,但覆盖 NotifyPropertyChanged(Of TResult) 以反映当前类将使 IntelliSense 工作。

【讨论】:

  • 您的编辑没有将Protected Shared Sub 中的myChangingPropertyName 更改为只是Name
  • @MarkHurd,感谢您了解此内容。我已经修复了错误,并且现在在我的程序中成功地使用了这个代码。感谢您的帮助。
  • 您需要将&lt;MethodImpl(MethodImplOptions.NoInlining)&gt; _ 添加到Protected Sub NotifyPropertyChanged 以帮助确保您获得正确的方法。事实上,该例程的调用者也需要应用它以完全确保它有效......
  • @MarkHurd,我不确定为什么需要这样做。你能进一步解释一下吗?
  • 当您使用优化编译并在没有调试器的情况下执行时,JIT 可能内联方法:An early Google hit; When it doesn't happen; A * link