Reputation: 35
I've run into an issue where I need to get the name of a property for logging purposes. I'm sure there is a way to do this in VB.Net using some amalgam of reflection and lambda expressions, but I've been unsuccessful so far.
What I'm trying to do is convert this:
objAddress.AddressLine
to this:
"AddressLine"
Upvotes: 3
Views: 11226
Reputation: 1
Using the System.Runtime.CompilerServices works wonders in this case, as of Net4.5. [See Caller Information] The optional CallerMemberName string can be used to identify what method/property called the log.
From MSDN
Private Sub DoProcessing()
TraceMessage("Something happened.")
End Sub
Public Sub TraceMessage(message As String,
<System.Runtime.CompilerServices.CallerMemberName> Optional memberName As String = Nothing,
<System.Runtime.CompilerServices.CallerFilePath> Optional sourcefilePath As String = Nothing,
<System.Runtime.CompilerServices.CallerLineNumber()> Optional sourceLineNumber As Integer = 0)
System.Diagnostics.Trace.WriteLine("message: " & message)
System.Diagnostics.Trace.WriteLine("member name: " & memberName)
System.Diagnostics.Trace.WriteLine("source file path: " & sourcefilePath)
System.Diagnostics.Trace.WriteLine("source line number: " & sourceLineNumber)
End Sub
' Sample output:
' message: Something happened.
' member name: DoProcessing
' source file path: C:\Users\username\Documents\Visual Studio 2012\Projects\CallerInfoVB\CallerInfoVB\Form1.vb
' source line number: 15
Different implementation showing results from a Property Call
Class Foo
Public ReadOnly Property ThisPropertyObject As Object
Get
LogManager.Ping
Return Nothing
End Get
End Property
Sub New()
Dim this = ThisPropertyObject
End Sub
End Class
Public Module LogManager
Public Sub Ping(<CallerMemberName> Optional memberName As String = Nothing,
<CallerFilePath> Optional sourcefilePath As String = Nothing,
<CallerLineNumber> Optional sourceLineNumber As Integer = 0)
Trace.Writeline(String.Format("[{0}]|{1}|LN:{2}] <PING>",
Path.GetFileName(sourcefilePath),
memberName,
sourceLineNumber)
)
)
End Sub
End Module
'! Results from 'DebugView'
' [20692][LogTestFile.vb|ThisPropertyObject|LN:62] <PING>
Upvotes: 0
Reputation: 4389
For someone who is still looking for an elegant solution, in the latest version of VB and C# you can use "nameof()".
C#:
var propertyName = nameof(objAddress.AddressLine)
VB .NET:
Dim propertyName = nameof(objAddress.AddressLine)
Note that if you do not have an instance of an object you can just use it's class name.
Upvotes: 4
Reputation: 4155
In the past, I've used a method I found online for doing this with INotifyPropertyChanged
. I can't remember exactly where, but this details the same resolution:
http://paulstovell.com/blog/strong-property-names
C#
public class Test : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _Name;
public string Name
{
get { return _Name; }
set
{
_Name = value;
RaisePropertyChanged(() => Name);
}
}
private void RaisePropertyChanged(Expression<Func<object>> property)
{
MemberExpression exp = property.Body as MemberExpression;
if (exp != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(exp.Member.Name));
}
}
}
VB
Public Class Test
Implements INotifyPropertyChanged
Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
Private _Name As String
Public Property Name() As String
Get
Return _Name
End Get
Set(value As String)
_Name = value
RaisePropertyChanged(Function() Me.Name)
End Set
End Property
Private Sub RaisePropertyChanged(Of T)(propertyName As Expression(Of Func(Of T)))
Dim exp As MemberExpression = TryCast(propertyName.Body, MemberExpression)
If exp IsNot Nothing Then
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(exp.Member.Name))
End If
End Sub
End Class
The main benefit of doing this is refactoring. If I ever rename my property, the Lambda (and by extension NotifyPropertyChanged event) changes automatically.
Update (2015)
It may be worth mentioning that the new features in Visual Studio 2015 make this even easier. Below is the same code shown above, but using the new nameof
feature (Details of this, and of other new features can be found Here).
C#
public class Test : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
string _Name;
public string Name
{
get { return _Name; }
set
{
_Name = value;
RaisePropertyChanged(nameof(Name));
}
}
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
VB
Public Class Test
Implements INotifyPropertyChanged
Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
Private _Name As String
Public Property Name() As String
Get
Return _Name
End Get
Set(value As String)
_Name = value
RaisePropertyChanged(NameOf(Name))
End Set
End Property
Private Sub RaisePropertyChanged(propertyName As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
End Class
You can even use nameof
on the subscriber side, in order to determine if the property is the one you care about:
private static void PropChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(Test.Name))
{
Console.WriteLine("The Property I care about changed");
}
}
Upvotes: 5
Reputation: 35
I decided to go with the_lotus's response to my initial question which was to use a constant. If I find a more dynamic way to do this in the near future I'll try to post it. lotus, if you happen to see this an answer the question with your comment, i'll switch the answered status over to you.
Upvotes: 0
Reputation: 3284
This will show the current Method. You may want to replace the "get_" prefix of the property name.
Public Class People
Public Shared ReadOnly Property Address As String
Get
Return System.Reflection.MethodInfo.GetCurrentMethod().ToString()
End Get
End Property
End Class
' print it
System.Diagnostics.Debug.Print(People.Address)
Upvotes: 2
Reputation: 803
From MSDN
Imports System
Imports System.Reflection
Class MyClass1
Private myProperty1 As Integer
' Declare MyProperty.
Public Property MyProperty() As Integer
Get
Return myProperty1
End Get
Set(ByVal Value As Integer)
myProperty1 = Value
End Set
End Property
End Class 'MyClass1
Public Class MyTypeClass
Public Shared Sub Main(ByVal args() As String)
Try
' Get Type Object corresponding to MyClass.
Dim myType As Type = GetType(MyClass1)
' Get PropertyInfo object by passing property name.
Dim myPropInfo As PropertyInfo = myType.GetProperty("MyProperty")
' Display Name propety to console.
Console.WriteLine("The {0} property exists in MyClass.", myPropInfo.Name)
Catch e As NullReferenceException
Console.WriteLine("The property does not exist in MyClass.", e.Message.ToString())
End Try
End Sub 'Main
End Class 'MyTypeClass
Upvotes: 0