I'm having trouble figuring out how to ask this question (the title is not worded well), so let me start with an example using the NameOf()
method, because it does something similar to what I'm trying to accomplish.
If I have a class like this:
Public Class MyClass
Public Property Foo As Bar
End Class
and then I declare an instance of it Dim instance As New MyClass
, I can then use the NameOf()
method in one of two ways:
' Both of these lines will print "Foo"
Console.WriteLine(NameOf(instance.Foo))
Console.WriteLine(NameOf(MyClass.Foo))
I would like to implement a method that can accept similar types of parameters, but I cannot figure out how. Here is the (extension) method I wrote:
<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
Using my above example, I can use it like this:
' Prints "MyClass.Foo"
Console.WriteLine(instance.GetPathOfProperty(Function() instance.Foo))
' Prints "MyClass.Foo.SomeBarProperty"
Console.WriteLine(instance.GetPathOfProperty(Function() instance.Foo.SomeBarProperty))
I would like to create another version of this method that is not an extension method, but rather a static method that can be called like (or similar to) this:
Console.WriteLine(GetPathOfProperty(Function() MyClass.Foo) ' Prints "MyClass.Foo"
This way I'd be able to use the function without actually creating an instance of MyClass
first. And this is where I need help. Since MyClass
is not a static class, I'm not able to put MyClass.Foo
in the function call. My first thought was to use Reflection, but I can't figure out how. Is there a parameter type I could use to allow me to do this (and if so, how would that look)? Or is this just a pipe-dream and not possible?
You can't pass in a direct reference to a property on a type, but you can cheat using lambda expressions (Function delegates) by typing the parameter to the delegate (essentially a static open instance delegate ).
Here is my module to return a path reference from an instance or from a type:
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
Which you can use like so:
Dim cf = New CInstance()
Dim ipe = PropertyExt.GetPathOfInstanceProperty(Function() cf.Foo.SomeBarProperty)
Dim tpe = PropertyExt.GetPathOfTypeProperty(Function(i As CInstance) i.Foo.SomeBarProperty)
NOTE: VB also seems to rename local variables so I added some code to drop the $VB$Local_
prefix from names - this can be removed if not needed.
PS This seems a lot cleaner/simpler in C# ;)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.