How to access the custom attributes of a property using VB.NET

I have a solution in VB.NET where I am implementing some custom attributes . One of them is for properties, example:

Namespace Attributes
  <AttributeUsage(AttributeTargets.Property)>
  Public Class DescriptionAttribute : Inherits Attribute

    Sub New(Name As String)
        Me.Name = Name
    End Sub

    Public Property Name As String

  End Class
End Namespace

I need to access the Name of these attributes coming from the classes, so I created an extension function for the PropertyInfo, like this:

<Extension()>
Function GetDescription(Prop As PropertyInfo) As String
  Dim attr As DescriptionAttribute = Prop.GetCustomAttribute(GetType(DescriptionAttribute))
  If (attr IsNot Nothing) Then Return attr.Name
  Return Prop.Name
End Function

And I want to be able to use this function anywhere, such as in a Override Method ToString:

Public Class Foo

  <Description("Hello world with espace")>
  Public Property HelloWorld As String

  Public Overrides Function ToString() As String

    return $"{HelloWorld.GetDescription()} - {HelloWorld}";

  End Function

End Class

The problem is that I don't know how to do to access this attribute coming from the property. The only way I could do it would be if I did a search on an instance of the class, but I don't understand that it is the best way to do it in VB.

How to solve?

Author: Maniero, 2018-10-25

1 answers

You cannot use the extension method as directly as you tried, because the method applies only to types PropertyInfo, and the property HelloWorld is of type String, so you must first get the PropertyInfo from that property.

I did some research and saw that you can do this "manually" by taking the type of the class and then using the GetProperty() method. You can do this by using the property name, such as a String:

Dim propInfoManual As PropertyInfo = GetType(Foo).GetProperty("HelloWorld")

Or you can use the operator NameOf, which avoids typos, which will be noticed already at compile time:

Dim propInfoManual As PropertyInfo = GetType(Foo).GetProperty(NameOf(Foo.HelloWorld))

But, if you still want to do an extension method, you can do so if you are going to pass the property name as a String:

<Extension()>
Public Function GetPropInfo(Of T)(origem As T, prop As String) As PropertyInfo

   Return GetType(T).GetProperty(prop)

End Function

If you want that advantage of strong typing, which makes it possible to catch typos at compile time, in this case the thing gets more complicated and the only way I found was using the classes of construction/deconstruction of expressions lambda :

' Necessário para usar as classes de expressões lambda.
Imports System.Linq.Expressions

'[...]

<Extension()>
Public Function GetPropInfo(Of TSource, TProp)(origem As TSource,
                                               seletorProp As Expression(Of Func(Of TProp))
                                              ) As PropertyInfo

   Select Case seletorProp.Body.NodeType
      Case ExpressionType.MemberAccess
         Dim memExp As MemberExpression = DirectCast(seletorProp.Body, MemberExpression)
         Return DirectCast(memExp.Member, PropertyInfo)
      Case Else
         Throw New ArgumentException()
   End Select

End Function

To test the three methods:

Public Class Foo

   <Description("Hello world with space")>
   Public Property HelloWorld As String

   Public Function DescricaoPropriedade() As String

      Dim descManual As String = GetType(Foo).GetProperty(NameOf(Foo.HelloWorld)).GetDescription()
      Dim descExtStr As String = Me.GetPropInfo("HelloWorld").GetDescription()
      Dim descExtLambda As String = Me.GetPropInfo(Function() Me.HelloWorld).GetDescription()

      Return $"Desc manual: {descManual} {vbCrLf}" &
             $"Desc estendido (str): {descExtStr} {vbCrLf}" &
             $"Desc estendido (lambda): {descExtLambda}"

   End Function

End Class

You can also use the extension method with lambda without the Me., I put it just to get more didactic.

Sources:

Edition

At the time I did not visualize, but now I realized that it is possible to use the simplest solution of extension, with parameter String instead of expression lambda , and still have strong typing, using here also the operator NameOf:

Dim descExtStr As String = Me.GetPropInfo(NameOf(HelloWorld)).GetDescription()
 1
Author: Pedro Gaspar, 2018-11-02 13:20:37