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

Asked

Viewed 161 times

1

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 those attributes coming from the classes, so I created an extension function for the PropertyInfo, thus:

<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 that function anywhere, like in a Override of the 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 I don’t know how to access this attribute from the property. The only way I could it would be if I did a search in a class instance, but I do not understand that it is the best way to do in VB.

How to solve?

1 answer

1


It is not possible to use the extension method as directly as you tried, because the method applies only to types PropertyInfo, and the property HelloWorld is the type String, so it is first necessary to obtain the PropertyInfo of that property.

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

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

Or you can use the operator NameOf, which avoids typing errors, which will be noticed already at compilation 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 name of the property 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 by using the expression construction/deconstruction classes 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 only 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 extension solution, 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()

Browser other questions tagged

You are not signed in. Login or sign up in order to post.