¿Cuál es una buena manera de comparar dos interfaces (IControl)? ¿Es esto un error en Delphi?
En el código fuente de Delphi, veo lo siguiente en la unidad ‘FMX.Forms’:
procedure TCommonCustomForm.SetHovered(const Value: IControl);
begin
if (Value <> FHovered) then
begin
....
end;
end;
Creo que hacer Value <> FHovered
es fundamentalmente incorrecto porque Value <> FHovered
puede devolver verdadero y al mismo tiempo tanto Value
como FHovered
pueden apuntar al mismo objeto TControl
. ¿Estoy equivocado? (ten en cuenta que esto es lo que vi en la depuración).
Ahora una pregunta subsidiaria: ¿por qué dos interfaces IControl
pueden ser diferentes (desde el punto de vista de los punteros) pero apuntar al mismo TControl
?
Nota: a continuación se muestra un ejemplo que muestra cómo dos interfaces IControl
pueden ser diferentes (desde el punto de vista del puntero) y seguir apuntando al mismo objeto:
procedure TForm.Button1Click(Sender: TObject);
var LFrame: Tframe;
LControl: TControl;
LIControl1: IControl;
LIControl2: IControl;
begin
LFrame := TFrame.Create(nil);
LControl := LFrame;
LIControl1 := LFrame;
LIControl2 := LControl;
if LIControl1 <> LIControl2 then
raise Exception.Create('Boom');
end;
Ahora, ¿cuál podría ser la forma correcta de solucionar este error?
davy.ai
Sí, la declaración
Value<>FHovered
puede devolver verdadero incluso cuando tantoValue
comoFHovered
apuntan al mismo objeto. Esto se debe a queValue
yFHovered
son referencias de interfaz, lo que significa que mantienen una referencia al objeto al que apuntan en lugar de los propios objetos. Entonces, cuando comparamos dos referencias de interfaz, estamos comparando dos punteros, y si estos punteros apuntan al mismo objeto, la comparación aún devolverá verdadero aunque las dos referencias de interfaz sean diferentes.Para solucionar este problema, debemos comparar las direcciones del objeto subyacente en lugar de comparar las referencias de interfaz directamente. Podemos hacer esto llamando a la función
Addr
en las referencias de interfaz, que devolverá la dirección del objeto al que apuntan. La implementación corregida se vería así:Aquí, primero nos aseguramos de que
Value
yFHovered
no seannil
(para evitar acceder a un miembro de un punteronil
), y luego comparamos las direcciones de los objetos subyacentes usando la propiedadObj
de las referencias de interfaz.