Las Buddy classes son una técnica para añadir metadatos a clases que son generadas automáticamente por herramientas, ya sean estas herramientas del Visual Studio o herramientas externas; también son útiles para la segregación de responsabilidades.
La introducción de clases parciales, que permiten ampliar los miembros de una clase creada por una herramienta sin que volver a crear la clase se machaque nuestra personalización, es una gran idea, pero tiene un problema a la hora de modificar un miembro ya declarado. Si en vez de añadir nuevos miembros a una clase queremos añadir un atributo a un miembro ya existente nos encontramos con un problema, puesto que el atributo añadido a un miembro de la clase se borraría al regenerar la clase de nuevo.
Para solventar este problema tenemos las buddy clases. Estas son clases que amplían los metadados de otra clase, pudiendo definir el miembro de la clase a modificar dentro de la buddy y añadiéndole el atributo que corresponda.
Imaginemos que tenemos la siguiente clase generada por una plantilla T4 en VS:
Partial Public Class Clasificacion
Private _ID as String
Private Descripcion as String
Public Sub New(ByVal id As String)
End Function
Public Property ID() As String
End Property
Public Property Descripcion() As String
End Property
End Class
Queremos añadir un atributo de validación a la propiedad Descripcion, por lo que debemos crear una Buddy Class con esa propiedad sin implementación y asociar esa Buddy Class a la extensión de la clase parcial utilizando el atributo MetadataType.
Public Class ClasificacionMetadata
<StringLength(50, ErrorMessage:="El campo descripcion de una Clasificacion no puede superar los 50 caracteres.")> _
Public Property Descripcion() As String
Get
End Get
Set
End Set
End Property
End Class
<MetadataType(GetType(ClasificacionMetadata))> _
Partial Public Class Clasificacion
Public Function tieneDescricion As Boolean
Return not String.IsNullOrEmpty(Me.Descripcion)
End Function
End Class
Con esta definición, algunas tecnologías .NET recuperan el atributo MetadataType utilizando reflexión y obtendrán el atributo StringLengthAttribute de la Buddy Class cuando procesen la propiedad Descripcion de la clase generada.
Desgraciadamente, si nuestro código necesita procesar estos metadatos a través de la reflexión de tipos debemos programar explícitamente la posibilidad de que la clase parcial tenga asociado un MetadataType, recuperarlo y al procesar la clase parcial buscar en la clase Buddy su correspondencia para mirar si tiene algún atributo que extienda algún miembro. Esto es muy oscuro, aburrido y provoca que todo aquel que toque el codigo fuente de nuestro programa tenga conocimiento de la necesidad de este comportamiento. No me gusta.
Por suerte, .NET provee una manera de ampliar las descripciones de las clases administradas para que sean procesadas de forma transparente por el framework de reflexión de tipos.