使用类型而不是具体实例来访问属性
Use type to access properties instead of concrete instance
我不知道怎么问这个问题(标题措辞不好),所以让我从一个使用 NameOf()
方法的例子开始,因为它做的事情和我的类似我正在努力完成。
如果我有这样的class:
Public Class MyClass
Public Property Foo As Bar
End Class
然后我声明它的一个实例 Dim instance As New MyClass
,然后我可以通过以下两种方式之一使用 NameOf()
方法:
' Both of these lines will print "Foo"
Console.WriteLine(NameOf(instance.Foo))
Console.WriteLine(NameOf(MyClass.Foo))
我想实现一个可以接受相似类型参数的方法,但我不知道如何实现。
这是我写的(扩展)方法:
<Extension()>
Public Function GetPathOfProperty(Of T As Class, TProp)(myObj As T, prop As Expression(Of Func(Of TProp))) As String
Dim result As String = String.Empty
Dim foundName As String = String.Empty
Dim className As String = myObj.GetType().Name
Dim p As MemberExpression = TryCast(prop.Body, MemberExpression)
While p IsNot Nothing
If className = p.Member.DeclaringType.Name Then
foundName = className + "."
End If
result = foundName + p.Member.Name + "." + result
If Not String.IsNullOrEmpty(foundName) Then
Exit While
End If
p = TryCast(p.Expression, MemberExpression)
End While
Return IIf(String.IsNullOrEmpty(foundName), "", result.Substring(0, result.Length - 1))
End Function
使用我上面的例子,我可以这样使用它:
' Prints "MyClass.Foo"
Console.WriteLine(instance.GetPathOfProperty(Function() instance.Foo))
' Prints "MyClass.Foo.SomeBarProperty"
Console.WriteLine(instance.GetPathOfProperty(Function() instance.Foo.SomeBarProperty))
我想创建此方法的另一个版本,它不是扩展方法,而是可以像(或类似)这样调用的静态方法:
Console.WriteLine(GetPathOfProperty(Function() MyClass.Foo) ' Prints "MyClass.Foo"
这样我就可以使用该函数而无需首先实际创建 MyClass
的实例。这就是我需要帮助的地方。由于 MyClass
不是静态的 class,我无法将 MyClass.Foo
放入函数调用中。我的第一个想法是使用反射,但我不知道如何使用。是否有我可以使用的参数类型来允许我执行此操作(如果是,那看起来如何)?或者这只是一个 pipe-dream 而不可能?
你不能在类型上传递对 属性 的直接引用,但你可以通过将参数键入委托(本质上是静态 open instance delegate).
这是我的 return 来自实例或类型的路径引用的模块:
Public Module PropertyExt
<Extension()>
Public Function TrimStart(Byval src As String, starter As String) As String
Return If(src.StartsWith(starter), src.Substring(starter.Length), src)
End Function
Public Function GetPathOfInstanceProperty(Of TRes)(e As Expression(Of Func(Of TRes))) As String
Dim b = TryCast(e.Body, MemberExpression)
Dim ans = ""
Do
ans = b.Member.Name.TrimStart("$VB$Local_") & "." & ans
b = TryCast(b.Expression, MemberExpression)
Loop While (b IsNot Nothing)
Return ans.TrimEnd(".")
End Function
Public Function GetPathOfTypeProperty(Of T,TRes)(e As Expression(Of Func(Of T,TRes))) As String
Dim b = TryCast(e.Body, MemberExpression)
Dim ans = ""
Do
ans = b.Member.Name.TrimStart("$VB$Local_") & "." & ans
Dim tryB = TryCast(b.Expression, MemberExpression)
If tryB Is Nothing Then
Dim tryParm = TryCast(b.Expression, ParameterExpression)
If tryParm IsNot Nothing Then
ans = tryParm.Type.Name & "." & ans
End If
End If
b = tryB
Loop While (b IsNot Nothing)
Return ans.TrimEnd(".")
End Function
End Module
你可以这样使用:
Dim cf = New CInstance()
Dim ipe = PropertyExt.GetPathOfInstanceProperty(Function() cf.Foo.SomeBarProperty)
Dim tpe = PropertyExt.GetPathOfTypeProperty(Function(i As CInstance) i.Foo.SomeBarProperty)
注意:VB 似乎也重命名局部变量,因此我添加了一些代码以删除名称中的 $VB$Local_
前缀 - 如果不需要,可以将其删除。
PS 这在 C# 中似乎很多 cleaner/simpler ;)
我不知道怎么问这个问题(标题措辞不好),所以让我从一个使用 NameOf()
方法的例子开始,因为它做的事情和我的类似我正在努力完成。
如果我有这样的class:
Public Class MyClass
Public Property Foo As Bar
End Class
然后我声明它的一个实例 Dim instance As New MyClass
,然后我可以通过以下两种方式之一使用 NameOf()
方法:
' Both of these lines will print "Foo"
Console.WriteLine(NameOf(instance.Foo))
Console.WriteLine(NameOf(MyClass.Foo))
我想实现一个可以接受相似类型参数的方法,但我不知道如何实现。 这是我写的(扩展)方法:
<Extension()>
Public Function GetPathOfProperty(Of T As Class, TProp)(myObj As T, prop As Expression(Of Func(Of TProp))) As String
Dim result As String = String.Empty
Dim foundName As String = String.Empty
Dim className As String = myObj.GetType().Name
Dim p As MemberExpression = TryCast(prop.Body, MemberExpression)
While p IsNot Nothing
If className = p.Member.DeclaringType.Name Then
foundName = className + "."
End If
result = foundName + p.Member.Name + "." + result
If Not String.IsNullOrEmpty(foundName) Then
Exit While
End If
p = TryCast(p.Expression, MemberExpression)
End While
Return IIf(String.IsNullOrEmpty(foundName), "", result.Substring(0, result.Length - 1))
End Function
使用我上面的例子,我可以这样使用它:
' Prints "MyClass.Foo"
Console.WriteLine(instance.GetPathOfProperty(Function() instance.Foo))
' Prints "MyClass.Foo.SomeBarProperty"
Console.WriteLine(instance.GetPathOfProperty(Function() instance.Foo.SomeBarProperty))
我想创建此方法的另一个版本,它不是扩展方法,而是可以像(或类似)这样调用的静态方法:
Console.WriteLine(GetPathOfProperty(Function() MyClass.Foo) ' Prints "MyClass.Foo"
这样我就可以使用该函数而无需首先实际创建 MyClass
的实例。这就是我需要帮助的地方。由于 MyClass
不是静态的 class,我无法将 MyClass.Foo
放入函数调用中。我的第一个想法是使用反射,但我不知道如何使用。是否有我可以使用的参数类型来允许我执行此操作(如果是,那看起来如何)?或者这只是一个 pipe-dream 而不可能?
你不能在类型上传递对 属性 的直接引用,但你可以通过将参数键入委托(本质上是静态 open instance delegate).
这是我的 return 来自实例或类型的路径引用的模块:
Public Module PropertyExt
<Extension()>
Public Function TrimStart(Byval src As String, starter As String) As String
Return If(src.StartsWith(starter), src.Substring(starter.Length), src)
End Function
Public Function GetPathOfInstanceProperty(Of TRes)(e As Expression(Of Func(Of TRes))) As String
Dim b = TryCast(e.Body, MemberExpression)
Dim ans = ""
Do
ans = b.Member.Name.TrimStart("$VB$Local_") & "." & ans
b = TryCast(b.Expression, MemberExpression)
Loop While (b IsNot Nothing)
Return ans.TrimEnd(".")
End Function
Public Function GetPathOfTypeProperty(Of T,TRes)(e As Expression(Of Func(Of T,TRes))) As String
Dim b = TryCast(e.Body, MemberExpression)
Dim ans = ""
Do
ans = b.Member.Name.TrimStart("$VB$Local_") & "." & ans
Dim tryB = TryCast(b.Expression, MemberExpression)
If tryB Is Nothing Then
Dim tryParm = TryCast(b.Expression, ParameterExpression)
If tryParm IsNot Nothing Then
ans = tryParm.Type.Name & "." & ans
End If
End If
b = tryB
Loop While (b IsNot Nothing)
Return ans.TrimEnd(".")
End Function
End Module
你可以这样使用:
Dim cf = New CInstance()
Dim ipe = PropertyExt.GetPathOfInstanceProperty(Function() cf.Foo.SomeBarProperty)
Dim tpe = PropertyExt.GetPathOfTypeProperty(Function(i As CInstance) i.Foo.SomeBarProperty)
注意:VB 似乎也重命名局部变量,因此我添加了一些代码以删除名称中的 $VB$Local_
前缀 - 如果不需要,可以将其删除。
PS 这在 C# 中似乎很多 cleaner/simpler ;)