Comprender los ayudantes de clase (y registro) de Delphi

Una característica del lenguaje Delphi agregada hace algunos años (allá en Delphi 2005) llamada "Ayudantes de clase" está diseñada para permitirle agregar una nueva funcionalidad a una clase existente (o un registro) mediante la introducción de nuevos métodos a la clase (registro).

A continuación, verá algunas ideas más para ayudantes de clase + aprenderá cuándo y cuándo no usar ayudantes de clase.

Ayudante de clase para ...

En palabras simples, un ayudante de clase es una construcción que extiende una clase al introducir nuevos métodos en la clase ayudante. Un ayudante de clase le permite extender la clase existente sin modificarla o heredarla..

Para extender la clase TStrings de VCL, declararía e implementaría un asistente de clase como el siguiente:

 tipo TStringsHelper = ayudante de clase para TStrings público función Contiene (const aString: string): boolean; final; 

La clase anterior, llamada "TStringsHelper" es un ayudante de clase para el tipo TStrings. Tenga en cuenta que TStrings se define en Classes.pas, una unidad que está disponible de forma predeterminada en la cláusula de usos para cualquier unidad de formulario de Delphi, por ejemplo.

La función que estamos agregando al tipo TStrings usando nuestro ayudante de clase es "Contiene". La implementación podría verse así:

 función TStringsHelper.Contains (const aString: string): boolean; empezar resultado: = -1 IndexOf (aString); final; 

Estoy seguro de que ha usado lo anterior muchas veces en su código, para verificar si algunos descendientes de TStrings, como TStringList, tienen algún valor de cadena en su colección de Items.

Tenga en cuenta que, por ejemplo, la propiedad Items de un TComboBox o un TListBox es del tipo TStrings.

Una vez implementado el TStringsHelper y un cuadro de lista en un formulario (denominado "ListBox1"), ahora puede verificar si alguna cadena forma parte de la propiedad Elementos del cuadro de lista utilizando:

 Si ListBox1.Items.Contains ('alguna cadena') luego... 

Ayudantes de clase Go and NoGo

La implementación de los ayudantes de clase tiene algunos impactos positivos y algunos (podría pensar) negativos en su codificación.

En general, debe evitar extender sus propias clases, como si necesitara agregar alguna funcionalidad nueva a sus propias clases personalizadas, agregue las cosas nuevas en la implementación de la clase directamente, sin usar un ayudante de clase.

Por lo tanto, los ayudantes de clase están más diseñados para extender una clase cuando no puede (o no necesita) confiar en la herencia de clase normal y las implementaciones de interfaz.

Un ayudante de clase no puede declarar datos de instancia, como nuevos campos privados (o propiedades que leerían / ​​escribirían dichos campos). Agregar nuevos campos de clase está permitido.

Un ayudante de clase puede agregar nuevos métodos (función, procedimiento).

Antes de Delphi XE3 solo podía extender clases y registros, tipos complejos. Desde la versión Delphi XE 3 también puede extender tipos simples como entero o cadena o TDateTime, y tener construcciones como:

 var s: cadena; empezar s: = 'Ayudantes de Delphi XE3'; s: = s.UpperCase.Reverse; final; 

Escribiré sobre Delphi XE 3 simple type helper en el futuro cercano.

¿Dónde está mi ayudante de clase?

Una limitación para usar ayudantes de clase que pueden ayudarte a "dispararte en el pie" es el hecho de que puedes definir y asociar múltiples ayudantes con un solo tipo. Sin embargo, solo se aplica cero o un ayudante en cualquier ubicación específica del código fuente. Se aplicará el ayudante definido en el alcance más cercano. El alcance auxiliar de clase o registro se determina de la manera normal de Delphi (por ejemplo, de derecha a izquierda en la cláusula de usos de la unidad).

Lo que esto significa es que puede definir dos ayudantes de clase TStringsHelper en dos unidades diferentes, pero solo se aplicará una cuando se use realmente!

Si un ayudante de clase no está definido en la unidad donde utiliza sus métodos introducidos, lo que en la mayoría de los casos será así, no sabe qué implementación de ayudante de clase usaría realmente. Dos ayudantes de clase para TStrings, nombrados de manera diferente o que residen en unidades diferentes, pueden tener una implementación diferente para el método "Contiene" en el ejemplo anterior.

Usar o no?

Sí, pero tenga en cuenta los posibles efectos secundarios..

Aquí hay otra extensión útil para el ayudante de clase TStringsHelper mencionado anteriormente

 TStringsHelper = ayudante de clase para TStrings privado función GetTheObject (const una cuerda: cuerda): TObject; procedimiento SetTheObject (const una cuerda: cuerda; const Valor: TObject); público propiedad ObjectFor [const una cuerda : cuerda]: TObject leer GetTheObject escribir SetTheObject; final; ... función TStringsHelper.GetTheObject (const una cuerda: cuerda): TObject; var idx: entero; empezar resultado: = nulo; idx: = IndexOf (aString); Si idx> -1 luego resultado: = Objetos [idx]; final; procedimiento TStringsHelper.SetTheObject (const una cuerda: cuerda; const Valor: TObject); var idx: entero; empezar idx: = IndexOf (aString); Si idx> -1 luego Objetos [idx]: = Valor; final; 

Si ha estado agregando objetos a una lista de cadenas, puede adivinar cuándo usar la útil propiedad auxiliar anterior..