software - delphi technologies
Enums vs Const vs Class Const en la programaciĆ³n de Delphi (6)
Tengo un campo entero en un ClientDataSet y necesito comparar algunos valores, algo como esto:
Puedo usar const
const
mvValue1 = 1;
mvValue2 = 2;
if ClientDataSet_Field.AsInteger = mvValue1 then
o enums
TMyValues = (mvValue1 = 1, mvValue2 = 2);
if ClientDataSet_Field.AsInteger = Integer(mvValue1) then
o clase const
TMyValue = class
const
Value1 = 1;
Value2 = 2;
end;
if ClientDataSet_Field.AsInteger = TMyValues.Value1 then
Me gusta el enfoque de clase const pero parece que no es el camino delphi, así que quiero saber qué piensas
Algo que hay que tener en cuenta es la compatibilidad con versiones anteriores: las constantes de clase son relativamente nuevas para Delphi, por lo tanto, si el código tiene que ser compartido con versiones anteriores de las que están disponibles.
Normalmente uso tipos enumerados, con la diferencia de la tuya es que mi primera enumeración suele ser un elemento "indefinido" para representar NULL o 0 en un campo int.
TmyValues = (myvUndefined, myvDescription1, myvDescription2)
if ClientDataSet_Field.AsInteger = Ord(myvDescription1) then...
Para usar un poco de la respuesta de Jim McKeeth, si necesita mostrar al usuario una versión de texto visible, o si necesita convertir el texto seleccionado en el tipo enumerado, entonces una matriz es útil junto con el tipo:
const MYVALS: array [TmyValues ] of string = ('''', ''Description1'', ''Description2'');
A continuación, puede tener funciones de utilidad para establecer / obtener el tipo enumerado a / desde una cadena:
Function MyValString(const pMyVal:TmyValues):string;
begin
result := MYVALS[Ord(pMyVal)];
end;
Function StringToMyVal(const pMyVal:String):TMyValues;
var i:Integer;
begin
result := myvUndefined;
for i := Low(MYVALS) to High(MYVALS) do
begin
if SameText(pMyVal, MYVALS[i]) then
begin
result := TMyValues(i);
break;
end;
end;
end;
Continuando ... puede tener la rutina de dispersión para establecer un cuadro combinado / lista:
Procedure SetList(const DestList:TStrings);
begin
DestList.Clear;
for i := Low(MYVALS) to High(MYVALS) do
begin
DestList.Insert(MYVALS[i]);
end;
end;
En código: SetList (Combo1.Items) o SetList (ListBox1.Items) ..
Entonces, si está viendo el patrón aquí ... útiles funciones de utilidad que rodean su enumeración, entonces agrega todo a su propia clase y coloca esta clase en su propia unidad llamada MyValueEnumeration o whaterver. Usted termina con todo el código que rodea esta enumeración en un solo lugar y sigue agregando las funciones de utilidad cuando las necesita. Si mantiene la unidad limpia, no mezcle otras funciones no relacionadas, entonces será muy útil para todos los proyectos relacionados con esa enumeración.
Verás más patrones a medida que pase el tiempo y usarás la misma funcionalidad una y otra vez y construirás una mejor ratonera de nuevo.
Declaración:
type
TMyValues = class
type TMyEnum = (myValue1, myValue2, myValue3, myValue4);
const MyStrVals: array [TMyEnum] of string =
(''One'', ''Two'', ''Three'', ''Four'');
const MyIntVals: array [TMyEnum] of integer =
(1, 2, 3, 4);
end;
Uso:
if ClientDataSet_Field.AsInteger = TMyValues.MyIntVals[myValue1] then
Un reparto generalmente sería mi última opción.
Yo no diría que las constelaciones de clase no son del estilo Delphi. Es solo que han sido presentados recientemente a Delphi, y una gran cantidad de libros y artículos que encontrarás en Internet fueron escritos antes de su presentación, y por lo tanto no los verás ampliamente usados. Muchos desarrolladores de Delphi (yo diría que la mayoría) habrán comenzado a usar Delphi antes de que estuvieran disponibles, y por lo tanto no son lo primero que uno piensa.
tantas opciones! :-) prefiero enumeraciones y los uso rutinariamente como describes. una de las partes que me gusta es que puedo usarlas con un ciclo "for". Yo uso constantes de clase también, pero prefiero enumeraciones (incluso enumeraciones privadas) dependiendo de lo que estoy tratando de lograr.
TMyType=class
private const // d2007 & later i think
iMaxItems=1; // d2007 & later i think
private type // d2007 & later i think
TMyValues = (mvValue1 = 1, mvValue2 = 2); // d2007 & later i think
private
public
end;
Una opción en la que no ha pensado es usar una tabla de búsqueda en la base de datos y luego puede compararla con la cadena en la base de datos.
p.ej.
Select value, Description from tbl_values inner join tbl_lookup_values where tbl_values.Value = tbl_lookup_values.value
if ClientDataSet_Field.AsString = ''ValueIwant'' then
Al usar constantes, recomiendo asignar el tipo cuando el tipo de datos es un flotante numérico.
Delphi y otros idiomas no siempre evaluarán los valores correctamente si los tipos no coinciden ...
TMyValue = class
const
// will not compare correctly to float values.
Value1 = 1; // true constant can be used to supply any data type value
Value2 = 2; // but should only be compared to similar data type
// will not compare correctly to a single or double.
Value3 = 3.3; // default is extended in debugger
// will not compare correctly to a single or extended.
Value1d : double = Value1; // 1.0
Value2d : double = Value2; // 2.0
end;
Los valores de flotación comparados en las sentencias if () y while () se deben comparar con valores del mismo tipo de datos, por lo que es mejor definir una variable temporal o global del tipo float utilizado para cualquier instrucción de comparación (= <>).
Cuando se compara con el mismo tipo de datos flotantes, este formato es más confiable para operadores de comparación en cualquier lenguaje de programación, no solo en Delphi, sino en cualquier lenguaje de programación donde los tipos de flotación definidos varían de variable a constante.
Una vez que asigne un tipo, Delphi no le permitirá usar la variable para alimentar a otra constante, por lo que las constantes verdaderas son buenas para alimentar cualquier tipo de datos relacionados, pero no para comparar en loops y sentencias if, a menos que estén asignados y comparados con enteros valores.
*** Nota: Lanzar un valor de un tipo de flotación a otro puede alterar el valor almacenado de lo que ingresó para fines de comparación, por lo tanto, verifique con una prueba unitaria que realice un bucle al hacer esto.
Es desafortunado que Delphi no permita un formato de enumeración como ... TController: Integer = (NoController = 0, ncpod = 1, nextwave = 2);
o imponer el nombre del tipo para acceder a los valores de enumeración.
o permitir que se use una constante de clase como parámetro predeterminado en una llamada como ... función getControllerName (Controller: TController = TController.NoController): string;
Sin embargo, un enfoque más cauteloso que proporciona ambos tipos de acceso sería colocar la enumeración dentro de una clase.
TController = class
//const
//NoController : Integer = 1;
//ncpod : Integer = 2;
//nextwave : Integer = 3;
type
Option = (NoController = 0, ncpod = 1, nextwave = 2);
public
Class function Name( Controller : Option = NoController) : string; static;
end;
implementation
class function TController.Name( Controller : Option = NoController) : string;
begin
Result := ''CNC'';
if (Controller = Option.nextwave) then
Result := Result + '' Piranha''
else if (Controller = Option.ncpod) then
Result := Result + '' Shark'';
Result := Result + '' Control Panel'';
end;
Este enfoque aislará de manera efectiva los valores, proporcionará el enfoque estático y permitirá el acceso a los valores usando un bucle for ().
El acceso a los valores de una función flotante sería así ...
using TControllerUnit;
function getName( Controller : TController.Option = TController.Option.NoController) : string;
implementation
function getName( Controller : TController.Option = TController.Option.NoController) : string;
begin
Result := ''CNC'';
if (Controller = TController.Option.nextwave) then
Result := Result + '' Piranha''
else if (Controller = TController.Option.ncpod) then
Result := Result + '' Shark'';
Result := Result + '' Control Panel'';
end;