Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi else ifs werden übersprungen (https://www.delphipraxis.net/99399-else-ifs-werden-uebersprungen.html)

xZise 11. Sep 2007 17:56


else ifs werden übersprungen
 
Ich habe folgene Konstruktion:
Delphi-Quellcode:
      if (ReadInteger('Version', 'Major', 0) > Major) then
        Avaiable
      else if (ReadInteger('Version', 'Minor', 0) > Minor) then
        Avaiable
      else if (ReadInteger('Version', 'Release', 0) > Release) then
        Avaiable
      else if (ReadInteger('Version', 'Build', 0) > Build) then
        Avaiable;
Meine Frage an euch: Was würdet ihr sagen:
Wenn ich Version in der Ini-Datei "1.5.2.1" ist, und die andere Version (die Variablen) "1.5.1.0".
Sollte er ein "Avaible" ausführen?
Meinermeinung nach im Vergleich der "Releases" oder nicht?
Aber Delphi (im Debugmodus) springt vom 1. Vergleich an das Ende der Vergleiche => keine Meldung => Bug ?!

Oder ich unterschätze die Wirkungsweise des "else-ifs"?

PS: Hier der Kontext:
Delphi-Quellcode:
procedure TfrmUpdate.Button1Click(Sender: TObject);
  procedure Avaiable;
  begin
    MessageBox(Handle, PChar('A new version is avaiable'), PChar('Update possible'), MB_OK or MB_ICONINFORMATION);
  end;
var
  fs : TFileStream;
  Major, Minor, Release, Build: Integer;
  ini : TIniFile;
begin
  fs := TFileStream.Create(ExtractFilePath(ParamStr(0)) + 'info.ini', fmCreate);
  try
    ihDownload.Get(infoUrl, fs);
  finally
    FreeAndNil(fs);
  end;
  GetVersion(ParamStr(0), Major, Minor, Release, Build);
  with TIniFile(ExtractFilePath(ParamStr(0)) + 'info.ini') do
    try
      // START VON OBEN
      if (ReadInteger('Version', 'Major', 0) > Major) then
        Avaiable
      else if (ReadInteger('Version', 'Minor', 0) > Minor) then
        Avaiable
      else if (ReadInteger('Version', 'Release', 0) > Release) then
        Avaiable
      else if (ReadInteger('Version', 'Build', 0) > Build) then
        Avaiable;
      // ENDE VON OBEN
    finally
      Free;
    end;
end;

Dax 11. Sep 2007 18:04

Re: else ifs werden übersprungen
 
Mach mal spasseshalber aus den > ein paar >=.

Edit: alternativ könntest du deine Vergleiche auch verketten, statt eine lange if-Liste zu benutzen...

s-off 11. Sep 2007 18:05

Re: else ifs werden übersprungen
 
Zitat:

Zitat von xZise
Meinermeinung nach im Vergleich der "Releases" oder nicht?

Auf den ersten Blick - ja.
Da wäre es interessant, zu sehen, was wirklich in Deiner Ini-Datei bzw. Deiner Variablen steht.

xZise 11. Sep 2007 18:10

Re: else ifs werden übersprungen
 
Zitat:

Zitat von Dax
Mach mal spasseshalber aus den > ein paar >=.

Edit: alternativ könntest du deine Vergleiche auch verketten, statt eine lange if-Liste zu benutzen...

Der sinn eines Updates ist es aber nicht, die gleiche Version nochmal zu downloaden ;)
Und bei einer langen Kette funktioniert das auch nicht ;)
Oder wie hättest du sie verkettet?

Zitat:

Zitat von s-off
Zitat:

Zitat von xZise
Meinermeinung nach im Vergleich der "Releases" oder nicht?

Auf den ersten Blick - ja.
Da wäre es interessant, zu sehen, was wirklich in Deiner Ini-Datei bzw. Deiner Variablen steht.

Und das ist ein Grund für Delphi seine Grunsätze über Bord zu werfen?

Also: Ini zum Download
Und in den Variablen stehen die korrekten Werte.

Oder wirft er vielleicht eine Exception?
[edit]Moment ;) Das würde die AV erklären ^^ Aber warum macht er dass :([/edit]

Zitat:

Zitat von pstruh
Also nicht das es wirklich wichtig wäre, aber müsste die Prozedur nicht "available" benannt werden :stupid:

:mrgreen:

pstruh 11. Sep 2007 18:10

Re: else ifs werden übersprungen
 
Also nicht das es wirklich wichtig wäre, aber müsste die Prozedur nicht "available" benannt werden :stupid:

dominikkv 11. Sep 2007 18:12

Re: else ifs werden übersprungen
 
ohh.. -.- einfach ignorieren...

mirage228 11. Sep 2007 18:15

Re: else ifs werden übersprungen
 
Habe das bei mir mal so gelöst, das geht garantiert (bei dir kanns evtl probleme geben, wenn major kleiner ist und dann nur der Release größer oder so...)
Delphi-Quellcode:
function CompareValues(v1, v2: Integer): Integer;
begin
  if v1 = v2 then
    Result := 0 else
  if v1 > v2 then
    Result := -1 else
  Result := 1;
end;

////////////////////////

Result := CompareValues(OriginalMajor, RemoteMajor);
if Result = 0 then
begin
  Result := CompareValues(OriginalMinor, RemoteMinor);
  if Result = 0 then
  begin
    Result := CompareValues(OriginalRelease, RemoteRelease);
    if Result = 0 then
      Result := CompareValues(OriginalBuild, RemoteBuild);
  end;
end;
mfG
mirage228

xZise 11. Sep 2007 18:21

Re: else ifs werden übersprungen
 
Bei einer Verkettung:
Delphi-Quellcode:
(NewMajor > Major) or .... or (NewBuild > Build)
Hast du das Problem bei der Version "1.0.0.0" gegenüber "0.0.0.1". Wenn die 1. die zu updatende Datei ist wird er sagen, dass die 2. Version neuer ist (da 1 > 0 :stupid: )

Hmmm... bei meiner ist auch ein Bug drinne :(
Zitat:

0 > 1 = falsch
0 > 0 = falsch
0 > 0 = falsch
1 > 0 = wahr


Ah jetzt ^^ Wenn man beides einsetzt und als Operator "and" nimmt:
Zitat:

(falsch) and ... >> Abbruch

ringli 11. Sep 2007 18:21

Re: else ifs werden übersprungen
 
Ich stand letztens vor dem selben Problem und habe es so gelöst:
Delphi-Quellcode:
procedure VersionStrToInt(Version : String;
                          var Major, Minor, Release, Build : Integer);
var
  Len : Integer;       // Länge der gesamten Versionsinfo
  p1, p2, p3 : Integer; // Position der einzelnen Punkte
begin
  // Länge des Versionsstrings ermitteln
  Len := Length(Version);
  //Position der einzelnen Punkte ermitteln
  p1  := PosEx('.', Version, 1);
  p2  := PosEx('.', Version, p1 + 1);
  p3  := PosEx('.', Version, p2 + 1);
  // Die einzelnen Strings in Zahlen umwandeln
  Major  := StrToIntDef(Copy(Version,    1, p1 - 1     ), 0);
  Minor  := StrToIntDef(Copy(Version, p1 + 1, p2 - p1 - 1), 0);
  Release := StrToIntDef(Copy(Version, p2 + 1, p3 - p2 - 1), 0);
  Build  := StrToIntDef(Copy(Version, p3 + 1, Len       ), 0);
end;

.
.
.

// Versionsinformationen der installierten Version ermitteln
VersionStrToInt(GetVersion, MajorAct, MinorAct, ReleaseAct, BuildAct);
VersionAct := StrToIntDef(Format(FormatString,
                          [MajorAct, MinorAct, ReleaseAct, BuildAct]), 0);

// Versionsinformation der Version auf dem Server ermitteln
VersionStrToInt(VER, MajorSrv, MinorSrv, ReleaseSrv, BuildSrv);
VersionSrv := StrToIntDef(Format(FormatString,
                          [MajorSrv, MinorSrv, ReleaseSrv, BuildSrv]), 0);

// Meldung wenn Version auf Server aktueller
if VersionSrv > VersionAct then
  begin
  end;
[EDIT]
Sorry hatte vergessen eine dazugehörige Prozedur zu posten... :oops:

s-off 11. Sep 2007 18:23

Re: else ifs werden übersprungen
 
Zitat:

Zitat von xZise
Oder wirft er vielleicht eine Exception?

Ja, und zwar deshalb, weil Du nur
Delphi-Quellcode:
with TIniFile(ExtractFilePath(ParamStr(0)) + 'info.ini') do
schreibst, es aber
Delphi-Quellcode:
with TIniFile.Create(ExtractFilePath(ParamStr(0)) + 'info.ini') do
sein müsste; das 'Create' fehlt.

Dax 11. Sep 2007 18:27

Re: else ifs werden übersprungen
 
Zitat:

Zitat von xZise
Der sinn eines Updates ist es aber nicht, die gleiche Version nochmal zu downloaden ;)
Und bei einer langen Kette funktioniert das auch nicht ;)

Damit sprach ich auch den von die vermuteten Bug im Delphi-Debugger an...

Wie du um die Teilabfragen herumkommst: Berechne eine Versions-ID so:
Delphi-Quellcode:
funtion VersionID(Major, Minor, Release, Build: Word): Int64;
begin
  Result := Int64(Major) shl 48 or Int64(Minor) shl 32 or Release shl 16 or Build;
end;
Wenn du diese IDs vergleicht, hast du alles, was du über die else-ifs ausdrücken wolltest, implizit dabei.

shmia 11. Sep 2007 18:35

Re: else ifs werden übersprungen
 
Das Kernproblem lässt sich auch auf einen Integervergleich reduzieren:
Delphi-Quellcode:
function MakeVersion(major, minor, release, build:byte):Cardinal;
begin
   result := (major shl 24) or (minor shl 16) or (release shl 8) or build;
end;
if MakeVersion(ReadInteger('Version', 'Major', 0), ....) > MakeVersion(Major, Minor, ...) then
   Avaiable;
Kein Teil darf dann über 255 hinausgehen. (Aber Versionen wie 3.260.70.577 sind ja eher selten)
Sollte dies ein Problem sein, dann macht man eben einen Fliesskommazahlvergleich:
Delphi-Quellcode:
function MakeVersion(major, minor, release, build:integer):Double;
begin
   result := (((major * 10000.0) + minor) * 10000.0 +release)*10000.0 + build;
end;

ringli 11. Sep 2007 18:43

Re: else ifs werden übersprungen
 
Sory, hatte in meinem Beitrag eine dazugehörige Prozedur vergessen. Habe den Beitrag nochmal editiert.

xZise 11. Sep 2007 21:37

Re: else ifs werden übersprungen
 
Zitat:

Zitat von s-off
Zitat:

Zitat von xZise
Oder wirft er vielleicht eine Exception?

Ja, und zwar deshalb, weil Du nur
Delphi-Quellcode:
with TIniFile(ExtractFilePath(ParamStr(0)) + 'info.ini') do
schreibst, es aber
Delphi-Quellcode:
with TIniFile.Create(ExtractFilePath(ParamStr(0)) + 'info.ini') do
sein müsste; das 'Create' fehlt.

:wall: :stupid:

Zitat:

Zitat von shmia
Das Kernproblem lässt sich auch auf einen Integervergleich reduzieren:
Delphi-Quellcode:
function MakeVersion(major, minor, release, build:byte):Cardinal;
begin
   result := (major shl 24) or (minor shl 16) or (release shl 8) or build;
end;
if MakeVersion(ReadInteger('Version', 'Major', 0), ....) > MakeVersion(Major, Minor, ...) then
   Avaiable;

Und was bringt mir ein solcher Vergleich? (Auch an Dax)

Ich habe das so gemacht:
Delphi-Quellcode:
if (ReadInteger('Version', 'Major', 0) >= Major) and (ReadInteger('Version', 'Minor', 0) >= Minor) and (ReadInteger('Version', 'Release', 0) >= Release) and (ReadInteger('Version', 'Build', 0) > Build) then

Hawkeye219 11. Sep 2007 21:55

Re: else ifs werden übersprungen
 
Hallo Fabian,

angenommen, ich arbeite mit Version 1.0.0.42, und die .ini-Datei kündigt Version 2.0.0.0 an. Mit deinem Code aus Beitrag #1 erhalte ich ein Update, mit deinem neuen Code aus Beitrag #14 nicht mehr. Und das nur, weil die Build-Nummer der neuen Version nicht hoch genug ist...

Gruß Hawkeye

Dax 11. Sep 2007 22:14

Re: else ifs werden übersprungen
 
Zitat:

Zitat von xZise
Und was bringt mir ein solcher Vergleich? (Auch an Dax)

Durch die Umwandlung der verschiedenen Versionszahlen in einen Integer erreichst du genau das, was du willst: ein Vergleich VerA > VerB ergibt nur dann true wenn [u]mindestens eine[b] Versionszahl von VerB größer ist als die entsprechende Versionszahl aus VerA. Das ist einfache Arithmetik ;) Der Grund dafür ist simpel: du hast vier Zahlen A, B, C und D, die man als Werte der ersten, zweiten, ... Position eines Stellenwertsystems S1 ansehen kann. Durch die von uns vorgeschlagene Umwandlung der vier Zahlen in eine einzige transferierst du diese Zahlen A, B, C, D in ein anderes Stellenwertsystem S2, dass diesmal pro Stelle *mehr* Informationen enthalten kann. Da S1 und S2 wohlgeordnet sind, gelingt dieser Vergleich immer.

Oder anders gesagt: weil 10A + B > 10C + D das selbe ist wie (A > B and C >= D) or (A >= B and C > D) - was sich auf beliebig viele Stellen erweitern lässt ;)

Edit: unter der Vorraussetzung, dass A, B, C, D die eigenen Versionszahlen sind und E, F, G, H die auf dem Server, könnte dein Vergleich auch einfach not (A <= E and B <= F and C <= G and D <= H) sein.

xZise 11. Sep 2007 22:19

Re: else ifs werden übersprungen
 
Hi Hawkeye219 :)
Mist ^^ ich habe beim letzten Vergleich das = vergessen :) OOPs


Zitat:

Zitat von Dax
Zitat:

Zitat von xZise
Und was bringt mir ein solcher Vergleich? (Auch an Dax)

Durch die Umwandlung der verschiedenen Versionszahlen in einen Integer erreichst du genau das, was du willst: ein Vergleich VerA > VerB ergibt nur dann true wenn [u]mindestens eine[b] Versionszahl von VerB größer ist als die entsprechende Versionszahl aus VerA. Das ist einfache Arithmetik ;) Der Grund dafür ist simpel: du hast vier Zahlen A, B, C und D, die man als Werte der ersten, zweiten, ... Position eines Stellenwertsystems S1 ansehen kann. Durch die von uns vorgeschlagene Umwandlung der vier Zahlen in eine einzige transferierst du diese Zahlen A, B, C, D in ein anderes Stellenwertsystem S2, dass diesmal pro Stelle *mehr* Informationen enthalten kann. Da S1 und S2 wohlgeordnet sind, gelingt dieser Vergleich immer.

Oder anders gesagt: weil 10A + B &gt; 10C + D das selbe ist wie (A &gt; B and C &gt;= D) or (A &gt;= B and C &gt; D) - was sich auf beliebig viele Stellen erweitern lässt ;)

Edit: unter der Vorraussetzung, dass A, B, C, D die eigenen Versionszahlen sind und E, F, G, H die auf dem Server, könnte dein Vergleich auch einfach not (A <= E and B &lt;= F and C &lt;= G and D &lt;= H) sein.

Ich weiß ;) Aber wo liegt der Vorteil gegenüber den oben genannten Code (#14)?

Dax 11. Sep 2007 22:24

Re: else ifs werden übersprungen
 
Oben genannter Code enthält Fehler, obwohl er auf den ersten Blick richtig erscheinen mag - unser Code enthält keine Fehler, weil es gegen die Axiome der Mathematik verstieße ;)

shmias Code ist aber, zugegebenermaßen, fehleranfällig als der, den ich gepostet habe, gerade weil Build-Zahlen manchmal schon über die Byte-Grenze hinauswachen.

grenzgaenger 11. Sep 2007 22:34

Re: else ifs werden übersprungen
 
entweder du machst 'n INT vergleich wie DAX und shmia sagten, oder du hängst 'ne build Nr. hinten an, welche über deine versionen ständig heraufgezählt wird und frägst auf diese ab... projekt -- >optionen --> versionsinfo --> buildnummer
dann sieht deine versionsnummer so aus 1.5.2.368 und die nächst version z.b. so 2.1.13.428

in deiner ersten version, haste auf alle fälle den >= vergleich vergessen...

grüsse und noch viel erfolg

grenzgaenger 11. Sep 2007 22:36

Re: else ifs werden übersprungen
 
Zitat:

Zitat von Dax
shmias Code ist aber, zugegebenermaßen, fehleranfällig als der, den ich gepostet habe, gerade weil Build-Zahlen manchmal schon über die Byte-Grenze hinauswachen.

wohl eher häufig, aber was spricht dagegen, die build nummer als in zu implementieren? ca. 2 Mrd. builds, dürften für den otto normal programmierer genügen ;-) und die reicht ja in aller regel aus, um eine neue version eindeutig zu identifizieren ... :thumb:

Dax 11. Sep 2007 22:48

Re: else ifs werden übersprungen
 
Da hast du wohl Recht :) Aber für den Fall, dass man keine Build-Nummer benutzen will (oder die aus irgend einem Grund nicht konsequent hochzählt), wäre dann unser Vorschlag ebenfalls geeignet.

Sir Rufo 11. Sep 2007 23:19

Re: else ifs werden übersprungen
 
Hi,

diese Funktion liefert folgendes Ergebnis:

V1 < V2 -> -1
V1 = V2 -> 0
V1 > V2 -> 1

und zwar immer wenn die einzelnen Versions-Zahlen nicht größer sind, als in ein integer passt.
Wer es grösser mag und braucht, kann ja auch int64 nehmen.

Die Funktion stammt aus einem Projekt von mir, wo ich in einem VirtualStringTree u.a. nach Versions-Nummern sortieren lassen will.
Klappt übrigens auch hervorragend mit IP-Adressen (verwende ich in dem geleichen Projekt auch dafür) :wink:

cu

Oliver

Delphi-Quellcode:
function VersionCompareStr(const V1, V2 : string) : integer;
var
  tvSL,
  cvSL : TStrings;
  i    : integer;
  equal : boolean;
  tV1, tV2 : string;
begin
  tvSL := TStringList.Create;
  cvSL := TStringList.Create;
  try
    tV1 := V1;
    tV2 := V2;
    tV1 := StringReplace( tV1, ',', '.', [ rfReplaceAll ] );
    tV2 := StringReplace( tV2, ',', '.', [ rfReplaceAll ] );

    tV1 := StringReplace( tV1, '_', '.', [ rfReplaceAll ] );
    tV2 := StringReplace( tV2, '_', '.', [ rfReplaceAll ] );

    tvSL.Delimiter := '.';
    cvSL.Delimiter := '.';
    tvSL.DelimitedText := tV1;
    cvSL.DelimitedText := tV2;


    while tvSL.Count < cvSL.Count
    do
      tvSL.Add( '0' );
    while cvSL.Count < tvSL.Count
    do
      cvSL.Add( '0' );
    i := 0;
    RESULT := 0;
    equal := true;
    while ( i < tvSL.Count ) and equal
    do begin
      equal := StrToIntDef( tvSL.Strings[ i ], 0 ) = StrToIntDef( cvSL.Strings[ i ], 0 );
      if not equal
      then
        if StrToIntDef( tvSL.Strings[ i ], 0 ) < StrToIntDef( cvSL.Strings[ i ], 0 )
        then
          RESULT := -1
        else
          RESULT := 1;
      Inc( i );
    end;

  finally
    FreeAndNil( tvSL );
    FreeAndNil( cvSL );
  end;
end;

shmia 12. Sep 2007 09:51

Re: else ifs werden übersprungen
 
Ich würde mal sagen die beste Lösung ist die von Dax:
Delphi-Quellcode:
funtion VersionID(Major, Minor, Release, Build: Word): Int64;
begin
  Result := Int64(Major) shl 48 or Int64(Minor) shl 32 or Release shl 16 or Build;
end;
Kurz, knackig und effizient.

xZise 12. Sep 2007 14:16

Re: else ifs werden übersprungen
 
Jap :) Mir fiel gestern noch auf, dass er auch bei gleichen Versionen zuschlägt.
Gibt es denn sozusagen ein int64 als vorzeichenlose Ganzzahl?
Und eine Frage zu Int64: ist das erste Bit ein Vorzeichenbit? (Also 63 Bits für die Zahl?) Oder ist "0" dass minimum? (also "- (MAX_INT64 / 2)?)

s-off 12. Sep 2007 14:19

Re: else ifs werden übersprungen
 
@xZise:

Hattest Du wirklich das Create vergessen? Deine Bildchen waren nicht ganz aussagekräftig - bin mir nicht sicher, ob Du Deinen Kopf wegen Dir, oder wegen mir an der Wand zerschmetterst :stupid:

xZise 12. Sep 2007 14:25

Re: else ifs werden übersprungen
 
Zitat:

Zitat von s-off
bin mir nicht sicher, ob Du Deinen Kopf wegen Dir, oder wegen mir an der Wand zerschmetterst :stupid:

Nein :) Es war kein Create drinne :wall: Es bezog sich eher auf mich als auf dich :stupid:

s-off 12. Sep 2007 14:28

Re: else ifs werden übersprungen
 
Na dann bin ich ja froh :wink: - danke für's Feedback :-D

shmia 12. Sep 2007 15:31

Re: else ifs werden übersprungen
 
Zitat:

Zitat von xZise
Gibt es denn sozusagen ein int64 als vorzeichenlose Ganzzahl?

Leider nicht. (Zumindest Delphi Version <= 5.0)
Zitat:

Zitat von xZise
Und eine Frage zu Int64: ist das erste Bit ein Vorzeichenbit? (Also 63 Bits für die Zahl?)

Ja.


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:50 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz