I’m not really sure how to ask this question, but basically I want to know how to specify a class type generically such that I can type and paste code around.
For example I have the following code:
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
The idea is to have the last Sub be generic, that is to say, not specifically have to specify CustInfo in it’s definition. This way I can literally copy this code to any other class and it will work unmodified.
I’ve tried creating a property that returns the type of the class and using that, which predictably failed. I tried using TypeOf, Me, even ‘this’ on a long shot and nothing worked. It seems there has to be a way for the compiler to know this based on this error message which I get when I change the last sub to:
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.
The extension method being referred to is:
<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
So, as you can see the compiler correctly inferred what is going on, but still couldn’t work with it. The only type that seems unknown is TResult, but that type should be easily inferred based on the other information in the extension method that is known.
It may be impossible to generically specify a class type in the procedure definition, in which case I’ll modify the code every time I use it, but I’d rather not and learn something new in the process.
Based on what @Mark Hurd answered, I’ve come up with something that makes working with properties much easier. I decided to create a class, decorated with
MustInheritthat ImplementsINotifyPropertyChangedand includes all theNotifyPropertyChangedcode that is needed all set up with generics for maximum reuse and portability. I would love to hear some feedback on this solution. I don’t see any issues with it, but I could easily be missing something.Then calls to notify of a change in other properties would be
NotifyPropertyChanged(Me, Function(x) x.myChangingProperty)or if you want to notify that the current property is changing all that is needed isNotifyPropertyChanged(). AdditionallyNotifyPropertyChanged(Me, "myChaningProperty")andNotifyPropertyChanged("myChangingProperty")will also work. Finally ifNotifyPropertyChanged(Of TResult)is overridden to include the derived class, then a call likeNotifyPropertyChanged(Function(x) x.myChaningProperty)will work too.Also, I’ve found that
NotifyPropertyChanged(Me, Function(x) x.myChaningProperty)will work just fine, and will be checked by the compiler. However, IntelliSense doesn’t work forx. I find that strange since the compiler clearly knows whatxis because it will even correct capitalization of variables. It isn’t a deal-breaker, but overridingNotifyPropertyChanged(Of TResult)to reflect the current class will make IntelliSense work.