Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   OOP (https://www.clubdelphi.com/foros/forumdisplay.php?f=5)
-   -   set no funciona (https://www.clubdelphi.com/foros/showthread.php?t=88058)

doctorhd 08-04-2015 04:46:56

set no funciona
 
Hola a todos, tengo el siguiente código:
Código Delphi [-]

TEnumTypeData = (tyNone,tyCurrency, tyBoolean, tyDate, tyDateTime, tyFloat, tyInteger, tyString, tyExpandString, tyTime, tyBinaryData);

TClaveValor = record
      private
        FClave:string;
        FValueDefault:Variant;
        FValue:Variant;
        FTipo:TEnumTypeData;
        procedure SetClave(const Value:string);
        procedure SetValueDefault(const Value:variant);
        procedure SetValue(const Value:variant);
        procedure SetTipo(const Value:TEnumTypeData);
      public
        property Clave: string read FClave write SetClave;
        property ValueDefault: Variant read FValueDefault write SetValueDefault;
        property Value:Variant read FValue write SetValue;
        property Tipo: TEnumTypeData read FTipo write SetTipo;
    end;

  procedure TClaveValor.SetClave(const Value:string);
  begin
    FClave:=Value;
  end;

  procedure TClaveValor.SetValueDefault(const Value:variant);
  begin
    FValueDefault:=Value;
  end;

  procedure TClaveValor.SetValue(const Value:variant);
  begin
    FValue:=Value;
  end;

  procedure TClaveValor.SetTipo(const Value:TEnumTypeData);
  begin
    FTipo:=Value;
  end;

  type
    TArrayClaveValor = array of TClaveValor;


  type
    TConfigBDRegistro = class
    private
      FTipoServer:TClaveValor;
      FNameServer:TClaveValor;
      FRuta:TClaveValor;
      FProComunicacion:TClaveValor;
      FVendorLib:TClaveValor;
      FListCampos:TArrayClaveValor;
      procedure setListCamposBD(value:TArrayClaveValor);
      function getListCamposBD:TArrayClaveValor;
    public
      constructor Create;
      property TipoServer:TClaveValor read FTipoServer write FTipoServer;
      property NameServer:TClaveValor read FNameServer write FNameServer;
      property Ruta:TClaveValor read FRuta write FRuta;
      property ProComunicacion:TClaveValor read FProComunicacion write FProComunicacion;
      property VendorLib:TClaveValor read FVendorLib write FVendorLib;
      property ListCampos:TArrayClaveValor read getListCamposBD write setListCamposBD;
    end;

  constructor TConfigBDRegistro.Create;
  begin
    Setlength(FListCampos,5);{Dimencionamos el tamaño de la lista de campos}
  end;{constructor}

  procedure TConfigBDRegistro.setListCamposBD(Value:TArrayClaveValor);
  begin
    FTipoServer:=Value[0];
    FNameServer:=Value[1];
    FRuta:=Value[2];
    FProComunicacion:=Value[3];
    FVendorLib:=Value[4];
  end;{function}

  function TConfigBDRegistro.getListCamposBD:TArrayClaveValor;
  begin
    FListCampos[0]:=FTipoServer;
    FListCampos[1]:=FNameServer;
    FListCampos[2]:=FRuta;
    FListCampos[3]:=FProComunicacion;
    FListCampos[4]:=FVendorLib;
    result:=FListCampos;
  end;{function}

La clase almacena ciertos parámetros de conexión para una BD, el tema es que necesito recorrer los campos de la clase en un bucle, por esto implemento el campo FListCampos, que es un array de TClaveValor, el problema se suscita al asignar valores a los campos a través del array. Nunca ingresa al prodedure setListCamposBD, que es el encargado de asignar lo valores, la llamada que se realiza es la siguiente:

Código Delphi [-]
   ....
   vInicio:=Low(ListCampos);
   vFin:=High(ListCampos);
   {recorremos la lista de campos}
   for vIndice:=vInicio to vFin do begin
     ListCampos[vIndice].Value:='un Dato';{esta asignación no tiene efecto en el campo que se accede a través del array}
   end;{for}
  ....

Gracias de antemano por su ayuda.
Saludos...

olbeup 08-04-2015 08:54:27

No puede declarar procedimiento o funciones dentro de un Record.

cambia:
Código Delphi [-]
TClaveValor = record
por
Código Delphi [-]
TClaveValor = class
Y dentro del constructor tienes que crear el/los objectos

Un saludo.

ecfisa 08-04-2015 10:41:50

Hola olbeup.
Cita:

Empezado por olbeup (Mensaje 490963)
No puede declarar procedimiento o funciones dentro de un Record.

Mi primer impulso fué hacer exáctamente la misma observación. Pero me abstuve de decir algo por que tengo un Delphi viejito :o y no conozco las últimas versiones.

Me puse a buscar sobre el tema y parece que ahora sí está permitido :eek: Language and Compiler Features Since Delphi 7

Debo reconocer que toma un gran parecido con la funcionalidad que en C++ tiene struct, donde la única diferencia con class es que los miembros de la primera son públicos por defecto y de la segunda lo son privados.

Lo que desconozco, y sería interesante saber, si también existe la herencia entre record como existe en el caso de struct y de ser así, de qué tipo.

Omnubilados saludos :)

Al González 08-04-2015 18:25:58

De momento no hay herencia en tipos registro, Daniel, ni hay planes para agregarla. Aunque en algunos casos es deseable que la hubiera. Los métodos en tipos registro llevan ya algunos años, incluso pueden ser métodos de clase, es decir, que se pueden llamar sin tener una instancia (variable) del tipo en cuestión.

Cabe mencionar que, en Delphi, la visibilidad predeterminada en una clase, es Public o Published, dependiendo de la directiva $TypeInfo/$M. Me permito colocar un extracto de la ayuda:
Cita:

If a member's declaration appears without its own visibility specifier, the member has the same visibility as the one that precedes it. Members at the beginning of a class declaration that don't have a specified visibility are by default published, provided the class is compiled in the {$M+} state or is derived from a class compiled in the {$M+} state; otherwise, such members are public.
Para doctorhd:

Tu método setListCamposBD no es llamado porque en la asignación
Código Delphi [-]
ListCampos[vIndice].Value := ...
ListCampos es una expresión de lectura, no de escritura. Es decir, estás leyendo la propiedad matriz ListCampos completa (lo cual llama al método getListCamposBD), y, una vez obtenida, accedes a su elemento de la posición vIndice, el cual, como nos has mostrado, es un record, para escribir el valor de su campo Value. En breves palabras, se lee un array para luego escribir sobre uno de sus elementos.

Tu diseño podría funcionar como esperas si cambias
Código Delphi [-]
TArrayClaveValor = array of TClaveValor;  // Matriz de registros TClaveValor
...
FListCampos[0] := FTipoServer;
por
Código Delphi [-]
TArrayClaveValor = array of ^TClaveValor;  // Matriz de punteros a registros TClaveValor
...
FListCampos[0] := @FTipoServer;
Pero aun así, en lo personal, me seguiría pareciendo un diseño extraño y no muy óptimo.

ecfisa:

Hace tiempo que barajo la idea de actualizar mi licencia de Delphi 2007 a XE7, y ver la forma de cedértela. Por lo pronto intenté adquirir la actualización en diciembre, pero el distribuidor local no ha atendido mi solicitud de compra (ignoro por qué una empresa no querría vender lo que dice vender). Como sea, este comentario nace del espíritu, que estoy seguro compartimos muchos aquí (y por ello lo hago público), de que sería estupendo que contaras con una versión más nueva de Delphi, dado que eres uno de los impulsores Delphi (independientes) más esmerados de la comunidad hispana. Quizá no sales mucho en la tele, pero tus aportaciones en estos foros no son nada baladíes.

Compañeros, imaginemos las contribuciones que podría hacer ecfisa si tuviera en sus manos un Delphi más actual. ¿Hacemos una cooperación? Si prefieren, y Daniel está de acuerdo, podemos tratar los detalles en privado. :)

Saludos.

Al González.

Casimiro Notevi 08-04-2015 18:40:35

Cita:

Empezado por Al González (Mensaje 490990)
Hace tiempo que barajo la idea de actualizar mi licencia de Delphi 2007 a XE7, y ver la forma de cedértela. Por lo pronto intenté adquirir la actualización en diciembre, pero el distribuidor local no ha atendido mi solicitud de compra (ignoro por qué una empresa no querría vender lo que dice vender). Como sea, este comentario nace del espíritu, que estoy seguro compartimos muchos aquí (y por ello lo hago público), de que sería estupendo que contaras con una versión más nueva de Delphi, dado que eres uno de los impulsores Delphi (independientes) más esmerados de la comunidad hispana. Quizá no sales mucho en la tele, pero tus aportaciones en estos foros no son nada baladíes.
Compañeros, imaginemos las contribuciones que podría hacer ecfisa si tuviera en sus manos un Delphi más actual. ¿Hacemos una cooperación? Si prefieren, y Daniel está de acuerdo, podemos tratar los detalles en privado. :)
Saludos.
Al González.

^\||/ .

AgustinOrtu 08-04-2015 18:55:56

Buenas, a mi me funciona, copie y pege tu implementacion tal cual e hice estas pruebas:

Código Delphi [-]
implementation

var
  Form3: TForm3;
  listCampos: TArrayClaveValor;

procedure TForm3.InicializarClick(Sender: TObject);
var
    i: integer;
    registro: TClaveValor;
begin
    SetLength(listCampos, 5);
    for i := 0 to 4 do
    begin
        registro.Value := Format('Prueba %d', [i]);
        listCampos[i] := registro;
    end;
end;

procedure TForm3.BtnRecorrerClick(Sender: TObject);
var
    registro: TClaveValor;
    i: integer;
begin
    for i := Low(listCampos) to High(listCampos) do
    begin
        listCampos[i].Value := ReverseString(listCampos[i].Value);
        ShowMessage(Listcampos[i].Value);
    end;
end;

Cuando llamo a ShowMessage me muestra el string invertido

Si no te entendi mal. Uso Delphi 2010

nlsgarcia 08-04-2015 19:08:16

Alberto,

Cita:

Empezado por Al
...eres uno de los impulsores Delphi (independientes) más esmerados de la comunidad hispana...tus aportaciones en estos foros no son nada baladíes...

Realmente Daniel es todo un maestro v:-)v

Cita:

Empezado por Al
...imaginemos las contribuciones que podría hacer ecfisa si tuviera en sus manos un Delphi más actual...

Quizás se pueda proponer que le otorguen el titulo de MVP y esto facilite el camino, aparte de ser un merecido reconocimiento a su labor de tantos años como impulsor de Delphi :rolleyes:

Saludos,

Nelson.

AgustinOrtu 08-04-2015 19:14:07

Totalmente de acuerdo, se merece un MVP

doctorhd 08-04-2015 20:02:41

Al González:
Cita:

Pero aun así, en lo personal, me seguiría pareciendo un diseño extraño y no muy óptimo.
Y de acuerdo a tu experiencia, que forma debería tomar la implementación para optimizar su funcionamiento...

Saludos...

ecfisa 08-04-2015 20:25:16

Hola.

Creo que son unos exagerados :D, aquí hay muchos que son mas merecedores de esas palabras.

Pero de todos modos les agradezco mucho, leer esas opiniones, es la mejor gratificación que cualquiera desearía tener :)

Saludos :)

mamcx 08-04-2015 22:57:22

Cita:

Empezado por doctorhd (Mensaje 491004)
Y de acuerdo a tu experiencia, que forma debería tomar la implementación para optimizar su funcionamiento...

No hablo por AL, pero este es un ejemplo muy tipico de la infección "classitis". Porque una cosa es como hacer esto tipo OO, y otra es darse cuenta que NO ES NECESARIO!

1- Estas usando un record como si fuera una clase
http://www.delphibasics.co.uk/Article.asp?Name=Records

2- Estas usando metodos y funciones & propiedades que no *aportan nada* que no te da un record gratis.
3- Generando mucho codigo para algo que se resuelve con 1 array, 2 record y un par de funciones.

Delphi no es Java! Puedes usar funciones, metodos y dejar de la lado la OO. Es un lenguaje "multi-paradigma", aunque obviamente esta mas enfocado al lado de la OO.

Te pongo un ejemplo:

Código Delphi [-]
type TEnumTypeData = (tyNone,tyCurrency, tyBoolean, tyDate, tyDateTime, tyFloat, tyInteger, tyString, tyExpandString, tyTime, tyBinaryData);

TClaveValor = record
  Clave: string;
  ValueDefault:Variant;
  Value:Variant;
  Tipo: TEnumTypeData;
end;

//TArrayClaveValor = array of TClaveValor;
TArrayClaveValor = TArray; {Aqui es un Array con Generics, pero no se ve que es Array (TClaveValor)}

TConfigBDRegistro = record
public
  TipoServer:TClaveValor;
  NameServer:TClaveValor;
  Ruta:TClaveValor;
  ProComunicacion:TClaveValor;
  VendorLib:TClaveValor;
  ListCampos:TArrayClaveValor;
end;

function createClaveValor(clave:string;tipo:TEnumTypeData; value, ValueDefault:Variant): TClaveValor;
begin
  //Construyes aqui
  result.Clave := clave;
  //etc
end;

function createConfigBD(
  nameServer, tipoServer, ruta, proComunicacion, VendorLib:TClaveValor;
  ListCampos:TArrayClaveValor): TConfigBDRegistro;
begin
  //Construyes aqui
  result.NameServer := nameServer;
  //etc
end;

begin
  try
    { TODO -oUser -cConsole Main : Insert code here }
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

Nota lo siguiente:

- No necesitas hacer create de un record. Los record son tipos "Value" like un string. Por eso son mas livianos y eficientes en memoria
- Mucho codigo eliminado
- Centralizado en createXXXX todo el proceso, incluyendo las validaciones.
- Si tu Delphi soporta Generics, puedes usar TArray<> y te ganas un constuctor + todo lo que te dan las clases genericas, lo que te ahorra otra clase ;)

Código Delphi [-]
TArrayClaveValor.Create(TClaveValor1, TClaveValor2, TClaveValor3);
En resumen: Usa clases cuando necesites la funcionalidad de clases.

doctorhd 09-04-2015 00:19:57

En un principio TClaveValor era un siempre record sin propiedades, pero al asignarlo como campo a la clase me enviaba el siguiente error:

Código Delphi [-]
e2064 left side cannot be assigned to

y por tal motivo tuve que transformarlo a su forma actual. Respecto a la conveniencia de utilizar registros en vez de clases, sin duda lo hago cuando el caso lo amerita, pero en este caso en particular necesito encapsular los datos contenidos y realizar algunas tareas con ellos, cosa que puedo hacer con funciones como me sugieren, pero prefiero que todo quede dentro de una clase, ya que dichas funciones solo sirven al tratamiento de dicha clase...

Saludos...

doctorhd 09-04-2015 06:58:00

Bueno finalmente mi diseño quedo de la siguiente forma:
Código Delphi [-]

TEnumTypeData = (tyNone,tyCurrency, tyBoolean, tyDate, tyDateTime, tyFloat, tyInteger, tyString, tyExpandString, tyTime, tyBinaryData);

TClaveValor = record
      private
        FClave:string;
        FValueDefault:Variant;
        FValue:Variant;
        FTipo:TEnumTypeData;
        procedure SetClave(const Value:string);
        procedure SetValueDefault(const Value:variant);
        procedure SetValue(const Value:variant);
        procedure SetTipo(const Value:TEnumTypeData);
      public
        property Clave: string read FClave write SetClave;
        property ValueDefault: Variant read FValueDefault write SetValueDefault;
        property Value:Variant read FValue write SetValue;
        property Tipo: TEnumTypeData read FTipo write SetTipo;
    end;

  procedure TClaveValor.SetClave(const Value:string);
  begin
    FClave:=Value;
  end;

  procedure TClaveValor.SetValueDefault(const Value:variant);
  begin
    FValueDefault:=Value;
  end;

  procedure TClaveValor.SetValue(const Value:variant);
  begin
    FValue:=Value;
  end;

  procedure TClaveValor.SetTipo(const Value:TEnumTypeData);
  begin
    FTipo:=Value;
  end;

 type PClaveValor = ^TClaveValor;{Puntero a TClaveValor }

 type
    TConfigBDRegistro = class
    private
      FTipoServer:TClaveValor;
      FNameServer:TClaveValor;
      FRuta:TClaveValor;
      FProComunicacion:TClaveValor;
      FRutaVendorLib:TClaveValor;
      FListCampos:array of PClaveValor;
      function GetCampo(const Index: Integer): PClaveValor;
      procedure SetCampo(const Index: Integer; const Value: PClaveValor);
      function GetNCampos:Integer;
    public
      constructor Create;
      property TipoServer:TClaveValor read FTipoServer write FTipoServer;
      property NameServer:TClaveValor read FNameServer write FNameServer;
      property Ruta:TClaveValor read FRuta write FRuta;
      property ProComunicacion:TClaveValor read FProComunicacion write FProComunicacion;
      property RutaVendorLib:TClaveValor read FRutaVendorLib write FRutaVendorLib;
      property ListCampos[const Index: Integer]:PClaveValor read GetCampo write SetCampo;
      property NCampos:Integer read GetNCampos;
    end;

  constructor TConfigBDRegistro.Create;
  begin
    Setlength(FListCampos,5);{Dimencionamos el tamaño de la lista de campos}
    FListCampos[0]:=@FTipoServer;
    FListCampos[1]:=@FNameServer;
    FListCampos[2]:=@FRuta;
    FListCampos[3]:=@FProComunicacion;
    FListCampos[4]:=@FRutaVendorLib;
  end;{constructor}

  function TConfigBDRegistro.GetCampo(const Index:Integer):PClaveValor;
  begin
    Result:=FListCampos[Index];
  end;{function}

  procedure TConfigBDRegistro.SetCampo(const Index:Integer; const Value:PClaveValor);
  begin
    FListCampos[Index]:=Value;
  end;{function}

  function TConfigBDRegistro.GetNCampos:Integer;
  begin
    Result:=High(FListCampos);
  end;{function}

Para ser llamado asi:

Código Delphi [-]
  ....
   vFin:=ConfigBDRegistro.NCampos;
   {recorremos la lista de campos}
   for vIndice:=0 to vFin do begin
     ListCampos[vIndice].Value:='un Dato';{Funciona}
   end;{for}
  ....

Un comentario acerca de lo dicho por mamcx
Cita:

1- Estas usando un record como si fuera una clase
Si, pero el lenguaje lo permite y lo implementa como una opción, por tanto porque no utilizarlo...

Creo que mamcx tiene razón en varios de los comentarios que hace, referente a simplificar el diseño utilizando solo record y funciones, ahora la pregunta es cuando programar O.O y cuando programar procedimientalmente... En mi caso mi aprendizaje fue enfocado a este ultimo, pero he ido cambiando de paradigma, por las enormes ventajas que representa programar O.O. herencia, encapsulacion, etc... Quizas utilizar lo mejor de ambos modelos...????

Saludos...

AgustinOrtu 09-04-2015 07:23:37

Yo no me voy a cansar de decirlo

Una base de datos SQLite, con una simple tabla

Código Delphi [-]
type
  TConfigRecord = record
    TuDato1: Integer;
    TuDato2: string;
    TuDato3: boolean;
  end;  

procedure LoadConfig(var Config: TConfigRecord);
var
  FQuery: TFDQuery;
begin
  with FQuery.Create(NIL) do
  begin
    FQuery.Connection := SQLiteConn;
    FQuery.SQL.Text := ' SELECT * FROM Config ';
    Open;
    with Config do
    begin
       TuDato1 := FieldByName('Campo1').AsInteger;
       TuDato2 := FieldByName('Campo2').AsString;
       TuDato3 := FieldByName('Campo3').AsBoolean; 
    end; 
    Free;
  end;
end;

procedure SaveConfig(Config: TConfigRecord);
var
  FQuery: TFDQuery;
begin
  with FQuery.Create(NIL) do
  begin
    FQuery.Connection := SQLiteConn;
    FQuery.SQL.Text := ' UPDATE Config SET ' +
                       ' Campo1 = :Valor1, ' 
                       ' Campo2 = :Valor2, ' 
                       ' Campo3 = :Valor3 '; 
    with Config do
    begin
       ParamByName('Valor1').AsInteger:= Config.TuDato1;
       ParamByName('Valor2').AsString:= Config.TuDato2;
       ParamByName('Valor3').AsBoolean:= Config.TuDato3;
    end; 
    Execute;
    Free;
  end;
end;

Mayor simpleza, potencia y seguridad es imposible

Saludos

olbeup 09-04-2015 09:21:41

Cita:

Empezado por ecfisa (Mensaje 490968)
Hola olbeup.

Mi primer impulso fué hacer exáctamente la misma observación. Pero me abstuve de decir algo por que tengo un Delphi viejito :o y no conozco las últimas versiones.

Me puse a buscar sobre el tema y parece que ahora sí está permitido :eek: Language and Compiler Features Since Delphi 7

Debo reconocer que toma un gran parecido con la funcionalidad que en C++ tiene struct, donde la única diferencia con class es que los miembros de la primera son públicos por defecto y de la segunda lo son privados.

Lo que desconozco, y sería interesante saber, si también existe la herencia entre record como existe en el caso de struct y de ser así, de qué tipo.

Omnubilados saludos :)

Hola ecfisa,

Pues a mi no me funciona y utilizo Delphi 7 sobre el enlaze Language and Compiler Features Since Delphi 7 que has puesto.

Cita:

In addition to fields, records now may have properties and methods (including constructors), class properties, class methods, class fields, and nested types.
Código Delphi [-]
type
  TMyRecord = record
    type
      TInnerColorType = Integer;
    var
      Red: Integer;
    class var
      Blue: Integer;
    procedure printRed();
    constructor Create(val: Integer);
    property RedProperty: TInnerColorType read Red write Red;
    class property BlueProp: TInnerColorType read Blue write Blue;
  end;

constructor TMyRecord.Create(val: Integer);
begin
  Red := val;
end;

procedure TMyRecord.printRed;
begin
  writeln('Red: ', Red);
end;

Me da error a partir del record en todas las líneas.

Un saludo.

nlsgarcia 09-04-2015 11:12:37

olbeup,

Cita:

Empezado por olbeup
...No puede declarar procedimiento o funciones dentro de un Record...

Es correcto ^\||/ , no se puede declarar procedimientos y funciones dentro de registros en Delphi 7.

Cita:

Empezado por olbeup
...sobre el enlaze Language and Compiler Features Since Delphi 7 que has puesto...a mi no me funciona y utilizo Delphi 7...

El enlace se refiere a nuevas características del lenguaje posteriores a Delphi 7 y por lo tanto no soportadas en Delphi 7, lo cual incluye more complex and "class-like" record types.

Revisa este código:
Código Delphi [-]
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TMathNum = record
    N1 : Double;
    N2 : Double;
    function SumNum : Double;
    procedure MsgNum;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function TMathNum.SumNum : Double;
begin
   Result := N1 + N2;
end;

procedure TMathNum.MsgNum;
begin
   ShowMessage('Delphi 2010 supports more complex and "class-like" record types');
end;

procedure TForm1.Button1Click(Sender: TObject);
var
   M : TMathNum;
begin
   M.N1 := 3.14;
   M.N2 := 2.71;
   ShowMessage(FloatToStr(M.SumNum));
   M.MsgNum;
end;

end.
El código anterior compila en Delphi 2010 pero no en Delphi 7 por todo lo expuesto anteriormente.

Espero sea útil :)

Nelson.

olbeup 09-04-2015 15:22:24

Aclarado, :D^\||/


La franja horaria es GMT +2. Ahora son las 18:16:22.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi