delphi types typecast-operator

delphi - ¿Cómo guardar/cargar Conjunto de Tipos?



types typecast-operator (9)

En Delphi, no es posible realizar una conversión de tipo de letra directamente, pero Delphi almacena el conjunto como un valor de byte. Al usar un movimiento sin tipo, es fácil copiarlo en un entero. Tenga en cuenta que estas funciones solo alcanzan un tamaño de 32 (límites de un entero). Para aumentar los límites, utilice Int64 en su lugar.

function SetToInt(const aSet;const Size:integer):integer; begin Result := 0; Move(aSet, Result, Size); end; procedure IntToSet(const Value:integer;var aSet;const Size:integer); begin Move(Value, aSet, Size); end;

Manifestación

type TMySet = set of (mssOne, mssTwo, mssThree, mssTwelve=12); var mSet: TMySet; aValue:integer; begin IntToSet(7,mSet,SizeOf(mSet)); Include(mSet,mssTwelve); aValue := SetToInt(mSet, SizeOf(mSet)); end;

Tengo este codigo

type TXSample = (xsType1, xsType2, xsType3, xsType4, xsType5, xsType6, xsType6, xsTyp7, xsType8); // up to FXSample30; .. private FXSample = Set of TXSample; .. published property Sample: TXSample read FXSample write FXSample; .. //if Sample has a value of Sample := [xsType2, xsType4, xsType5, xsType6, xsTyp7];

¿Cómo puedo guardar / cargar la propiedad de Muestra?
Me gustaría guardarlo en la base de datos.
¿Es posible?


La forma más fácil de almacenar el conjunto en la base de datos (como se menciona en @DavidHeffernan en el comentario) es convertir su conjunto en máscara de bits. en el valor int32 (entero), tiene 32 bits y puede guardar hasta 32 campos; Delphi tiene el tipo TIntegerSet (consulte http://docwiki.embarcadero.com/Libraries/en/System.SysUtils.TIntegerSet ) definido en SysUtils . se declara como:

TIntegerSet = set of 0..SizeOf(Integer) * 8 - 1;

así que, al usarlo, es fácil convertir el conjunto en entero y viceversa (solo se convierte TIngeterSet en entero o viceversa);

bit-mask también es una buena opción porque es solo un campo INT en su tabla de base de datos.

también puede crear una tabla separada en su base de datos para almacenar el contenido del conjunto (tabla principal (id, ...) y setValuesTable (main_id, setElementValue)) (esta opción es buena para usar en consultas de base de datos)

Aquí hay un ejemplo del uso de TIntegerSet :

program Project1; {$APPTYPE CONSOLE} uses System.SysUtils; type TXSample = (xsType1, xsType2, xsType3, xsType4, xsType5, xsType6, xsType7, xsType8); TSampleSet = set of TXSample; function SampleSetToInteger(ss : TSampleSet) : integer; var intset : TIntegerSet; s : TXSample; begin intSet := []; for s in ss do include(intSet, ord(s)); result := integer(intSet); end; function IntegerToSampleSet(mask : integer) : TSampleSet; var intSet : TIntegerSet; b : byte; begin intSet := TIntegerSet(mask); result := []; for b in intSet do include(result, TXSample(b)); end; var xs : TSampleSet; mask : integer; begin xs := [xsType2, xsType6 .. xsType8]; mask := SampleSetToInteger(xs); //integer mask xs := IntegerToSampleSet(mask); end.


La solución más simple: proceder con el conjunto directamente como variable numérica. El "absoluto" es una palabra clave:

procedure Foo(FXSample: TFXSample); var NumericFxSample: Byte absolute FXSample; begin WriteLn(YourTextFile, NumericFxSample);//numeric value from a set end;

Si su tipo es más ancho que 8 bits, necesita usar un tipo numérico más ancho como palabra (hasta 16 elementos en un conjunto) o dword.


Las variables establecidas se pueden guardar con éxito en un descendiente de TStream. Aquí hay un ejemplo.

Simplemente cree una nueva aplicación de formularios vcl, agregue dos componentes TButton y complete los eventos OnClick para cada botón como se ilustra en el siguiente ejemplo.

Esto se creó en XE4, por lo que la cláusula de usos puede ser diferente para otras versiones de Delphi, pero eso debería ser trivial de cambiar al eliminar los indicadores de espacio de nombres antes de cada unidad en la cláusula de usos. Guardar una variable de tipo conjunto con valores articulados es posible en un archivo binario y fácilmente con Delphi. En otras palabras,

También se sugiere echar un vistazo a la unidad TypInfo si tiene la fuente o simplemente usar las funciones proporcionadas que hacen que la disección de los tipos de Set a su representación de texto sea bastante simple, aunque aquí no se proporciona ningún ejemplo. Se sugiere si desea incluir guardar en un archivo de configuración o ini o en un formato de persistencia que se pueda editar con texto.

El de abajo es el más simple que conozco. Mirar la salida binaria de un tipo de conjunto guardado en una secuencia como la que se muestra a continuación implica que se guarda en la representación de mapa de bits más pequeña posible para el conjunto en función de su tamaño. El que se muestra a continuación se asigna a un byte en el disco (el valor es 5), lo que significa que cada valor debe asignarse a una potencia de 2 (seThis = 1, seThat = 2, seTheOther = 4) al igual que los valores enmascarados constantes creados manualmente. El compilador probablemente hace cumplir que sigue reglas que obligan a mantener su ordinalidad. Este ejemplo fue probado y funciona en Delphi XE4.

Espero que ayude.

Brian Joseph Johns

unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; type TSomeEnum = (seThis, seThat, seTheOther); TSomeEnumSet = set of TSomeEnum; TForm1 = class(TForm) Button1: TButton; Button2: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; SomeSetVar: TSomeEnumSet; SomeBoolean: Boolean; SomeInt: Integer; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); begin SomeSetVar := [seThis, seTheOther]; SomeBoolean := True; SomeInt := 31415; with TFileStream.Create(''SetSave.bin'',fmCreate or fmOpenWrite or fmShareCompat) do try Write(SomeSetVar,SizeOf(SomeSetVar)); Write(SomeBoolean,SizeOf(Boolean)); Write(SomeInt,SizeOf(Integer)); finally Free; end; SomeSetVar := []; SomeInt := 0; SomeBoolean := False; end; procedure TForm1.Button2Click(Sender: TObject); var ResponseStr: string; begin with TFileStream.Create(''SetSave.bin'',fmOpenRead or fmShareCompat) do try Read(SomeSetVar,SizeOf(SomeSetVar)); Read(SomeBoolean,SizeOf(Boolean)); Read(SomeInt,SizeOf(Integer)); finally Free; end; ResponseStr := ''SomeSetVar = ''; if (seThis in SomeSetVar) then ResponseStr := ResponseStr + ''seThis ''; if (seThat in SomeSetVar) then ResponseStr := ResponseStr + ''seThat ''; if (seTheOther in SomeSetVar) then ResponseStr := ResponseStr + ''seTheOther ''; ResponseStr := ResponseStr + '' SomeBoolean = '' + BoolToStr(SomeBoolean); ResponseStr := ResponseStr + '' SomeInt = '' + IntToStr(SomeInt); ShowMessage(ResponseStr); end; end.


O podemos hacer que el compilador se olvide completamente de los tipos y luego definir lo que debería ver (en caso de que sepamos en tiempo de compilación lo que debería ver). Esta solución es tan horrible como se puede escribir en una sola línea.

type // Controls.TCMMouseWheel relies on TShiftState not exceeding 2 bytes in size TShiftState = set of (ssShift, ssAlt, ssCtrl, ssLeft, ssRight, ssMiddle, ssDouble, ssTouch, ssPen, ssCommand, ssHorizontal); var Shifts : TShiftState; Value : Integer; begin Shifts := TShiftState((Pointer(@Value))^): Value := (PInteger(@Shifts))^; if ssShift in TShiftState((Pointer(@Value))^) then Exit; end;

Sucede que los bits no utilizados (arriba) se establecen (o no) pero no tiene influencia en las operaciones de set ( in , = , + , - , * ..).

Esta línea en Delfos:

Shifts := TShiftState((Pointer(@Value))^);

Es así en Assembler (Delphi XE6):

lea eax,[ebp-$0c] mov ax,[eax] mov [ebp-$06],ax

En Delphi 2007 (donde TShiftState es más pequeño para que se pueda usar Byte ), este ensamblador:

movzx eax,[esi] mov [ebp-$01],al


Personalmente, convertiría el conjunto en un entero y lo almacenaría en la base de datos como un campo INT , como otros sugirieron. @teran sugirió usar el tipo TIntegerSet , y aquí está mi enfoque trabajando con enteros nativos usando operaciones de bit.

Tenga en cuenta que puede usar SampleInInteger() para determinar si un elemento determinado de la enumeración está presente en la máscara de enteros generada por SampleSetToInteger() .

Aquí está el código:

program Project1; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; type { .: TXSample :. } TXSample = (xsType1 = 0, xsType2, xsType3, xsType4, xsType5, xsType6, xsType7, xsType8); // up to FXSample30; TXSampleSet = set of TXSample; // Converts a TXSampleSet to an integer. function SampleSetToInteger(const S: TXSampleSet): Integer; var Sample: TXSample; begin Result := 0; for Sample := Low(TXSample) to High(TXSample) do if (Sample in S) then Result := Result or (1 shl Ord(Sample)); end; // Converts an integer to TXSampleSet. function IntegerToSampleSet(const Int: Integer): TXSampleSet; var I: Integer; begin Result := []; for I := 0 to Ord(High(TXSample)) do if Int and (1 shl I) <> 0 then Result := Result + [TXSample(I)]; end; // Checks if a TXSample is present in the integer. function SampleInInteger(const S: TXSample; const Int: Integer): Boolean; begin Result := Int and (1 shl Ord(S)) <> 0; end; var XSample, XSample1: TXSampleSet; Tmp: Integer; begin XSample := [xsType2, xsType4, xsType5, xsType6, xsType7]; XSample1 := [xsType1]; Tmp := SampleSetToInteger(XSample); Writeln(Tmp); XSample1 := IntegerToSampleSet(Tmp); if (xsType5 in XSample1) then Writeln(''Exists''); if (SampleInInteger(xsType1, Tmp)) then Writeln(''Exists in int''); Readln; end.


Puede utilizar esta unidad para convertir set a int. Si necesita más funciones settoint, puede agregar la suya buscando el código a continuación.

El conjunto puede tomar solo 1 byte de espacio de memoria. Para que pueda obtener su tamaño de Set y obtener el resultado como modula de este resultado.

Ejemplo: su tamaño de conjunto: 1 byte puede obtener el resultado ->

Resultado: = pINT ^ mod maxVal

Debe obtener maxval calculando maxvalue de tipo variable.

maxVal = Power (2, (8 * sizeof (MySet) -1))

unit u_tool; interface uses Graphics; type TXSample = (xsType1, xsType2, xsType3, xsType4, xsType5, xsType6, xsType6, xsTyp7, xsType8); // up to FXSample30; FXSample = Set of TXSample; function FXSampleToInt(FXSample: FXSample ): Integer; function IntToFXSample(Value: Integer): FXSample; function FontStyleToInt(FontStyle: TFontStyles ): Integer; function IntToFontStyle(Value: Integer): TFontStyles; implementation function FXSampleToInt(FXSample: FXSample ): Integer; var pInt: PInteger; begin pInt := @FXSample; Result := pInt^; end; function IntToFXSample(Value: Integer): FXSample; var PFXSample: ^FXSample; begin PFXSample := @Value; Result := PFXSample^; end; function FontStyleToInt(FontStyle: TFontStyles ): Integer; var pInt: PInteger; begin pInt := @FontStyle; Result := pInt^; end; function IntToFontStyle(Value: Integer): TFontStyles; var PFontStyles: ^TFontStyles; begin PFontStyles := @Value; Result := PFontStyles^; end; end.


Siempre que su conjunto nunca exceda las 32 posibilidades ( Ord(High(TXSample)) <= 31 ), entonces es perfectamente Ord(High(TXSample)) <= 31 encasillar el conjunto en un Integer y viceversa:

type TXSamples = set of TXSample; var XSamples: TXSamples; begin ValueToStoreInDB := Integer(XSamples); Integer(XSamples) := ValueReadFromDB; end;

Para ser más específicos: SizeOf(TXSamples) tiene que ser exactamente igual a SizeOf(StorageTypeForDB) . Por lo tanto, los siguientes rangos se aplican a Ord(High(TXSample)) al realizar la conversión de TXSamples de TXSamples a:

  • Byte: Ord(High(TXSample)) < 8
  • Word: 8 <= Ord(High(TXSample)) < 16
  • Longword: 16 <= Ord(High(TXSample)) < 32
  • UInt64: 32 <= Ord(High(TXSample)) < 64

Un conjunto de Delphi es simplemente una colección de (posiblemente) banderas booleanas relacionadas. Cada indicador booleano corresponde a si el valor ordinal coincidente está o no en el conjunto.

Ciertamente, podría empaquetar un conjunto en un valor entero representando el conjunto como un conjunto de bits. O puedes crear una representación textual del conjunto.

Sin embargo, estas dos opciones no le permiten tener una capacidad manejable para consultar la base de datos en el nivel SQL. Por este motivo, le aconsejo que represente cada valor en el conjunto, es decir, cada indicador booleano, como un campo separado (es decir, columna) de la tabla de la base de datos. Esto le da la representación más poderosa de los datos.