簡體   English   中英

如何使用屬性本身獲取屬性的名稱

[英]How do you get the name of a property using the property itself

我遇到了一個問題,我需要獲取屬性的名稱以進行記錄。 我確信在 VB.Net 中有一種方法可以使用反射和 lambda 表達式的一些混合來做到這一點,但到目前為止我一直沒有成功。

我想要做的是轉換這個:

objAddress.AddressLine

對此:

"AddressLine"

過去,我使用了一種我在網上找到的方法來使用INotifyPropertyChanged執行此操作。 我不記得確切的位置,但這詳細說明了相同的分辨率:

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

這樣做的主要好處是重構。 如果我重命名我的屬性,Lambda(以及擴展 NotifyPropertyChanged 事件)會自動更改。


更新 (2015)

值得一提的是,Visual Studio 2015 中的新功能使這變得更加容易。 下面是上面示出的相同的代碼,但使用新的nameof特征(其細節,以及其他新功能可以找到這里)。

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

您甚至可以在訂閱者端使用nameof ,以確定該屬性是否是您關心的:

    private static void PropChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == nameof(Test.Name))
        {
            Console.WriteLine("The Property I care about changed");
        }
    }

對於仍在尋找優雅解決方案的人,在最新版本的 VB 和 C# 中,您可以使用“nameof()”。

C#:

var propertyName = nameof(objAddress.AddressLine)

VB.NET:

Dim propertyName = nameof(objAddress.AddressLine)

請注意,如果您沒有對象的實例,則可以使用它的類名。

這將顯示當前方法。 您可能想要替換屬性名稱的“get_”前綴。

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)

來自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 

我決定采用 the_lotus 對我最初使用常量的問題的回答。 如果我在不久的將來找到一種更動態的方法來做到這一點,我會嘗試發布它。 蓮花,如果你碰巧看到這個回答問題的評論,我會將回答狀態切換給你。

從 Net4.5 開始,在這種情況下使用 System.Runtime.CompilerServices 會產生奇跡。 [查看調用者信息] 可選的 CallerMemberName 字符串可用於標識調用日志的方法/屬性。

來自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

顯示屬性調用結果的不同實現

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> 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM