如何使用属性本身获取属性的名称

时间:2013-11-14 15:04:08

标签: vb.net reflection properties lambda

我遇到了一个问题,我需要获取用于记录目的的属性名称。我确信有一种方法可以在VB.Net中使用一些反射和lambda表达式来完成这个,但到目前为止我还没有成功。

我要做的是转换它:

objAddress.AddressLine

到此:

"AddressLine"

6 个答案:

答案 0 :(得分:5)

在过去,我使用了我在网上找到的方法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功能(可以找到详细信息以及其他新功能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

您甚至可以在订阅方使用nameof,以确定该属性是否属于您关注的属性:

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

答案 1 :(得分:4)

对于仍在寻找优雅解决方案的人,在最新版本的VB和C#中,您可以使用“nameof()”。

<强> C#:

var propertyName = nameof(objAddress.AddressLine)

VB .NET:

Dim propertyName = nameof(objAddress.AddressLine)

请注意,如果您没有对象的实例,则可以使用它的类名。

答案 2 :(得分:2)

这将显示当前的方法。您可能希望替换属性名称的“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)

答案 3 :(得分:0)

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

答案 4 :(得分:0)

我决定使用the_lotus对我最初使用常量的问题的回答。如果我在不久的将来找到一种更有活力的方式来做这件事,我会尝试发布它。莲花,如果你碰巧看到这个回答你的评论的问题,我会把回答的状态交给你。

答案 5 :(得分:0)

从Net4.5开始,在这种情况下,使用System.Runtime.CompilerServices可以实现奇迹。 [请参见Caller Information。可选的CallerMemberName字符串可用于标识调用日志的方法/属性。

来自 MSDN

let webdriver = require('selenium-webdriver');
let chrome = require('selenium-webdriver/chrome');
let chromedriver = require('chromedriver');

chrome.setDefaultService(new chrome.ServiceBuilder(chromedriver.path).build());

// let driver = new webdriver.Builder()
//     .withCapabilities(webdriver.Capabilities.chrome())
//     .build();
let options = webdriver.ChromeOptions;

options.add_argument("download.default_directory=C:/Downloads")

let driver = webdriver.chrome(options);

let figma = 'https://www.figma.com/';
driver.get (figma).then(
    backup
);

function backup() {
    driver.sleep(3000);
    driver.quit();
}

不同的实现显示了属性调用

的结果
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