es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿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?

Tags:  ,

Answer

  1. Avatar for davy.ai

    Sí, la declaración Value<>FHovered puede devolver verdadero incluso cuando tanto Value como FHovered apuntan al mismo objeto. Esto se debe a que Value y FHovered 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í:

    procedure TCommonCustomForm.SetHovered(const Value: IControl);
    begin
      if (Value <> nil) and (FHovered <> nil) and (Value.Obj <> FHovered.Obj) then
      begin
        // hacer algo
      end;
    end;
    

    Aquí, primero nos aseguramos de que Value y FHovered no sean nil (para evitar acceder a un miembro de un puntero nil), y luego comparamos las direcciones de los objetos subyacentes usando la propiedad Obj de las referencias de interfaz.

Comments are closed.