Laden...

double.Parse mit InvariantCulture liefert unerwarteten Wert

Erstellt von tequila slammer vor 14 Jahren Letzter Beitrag vor 14 Jahren 1.947 Views
T
tequila slammer Themenstarter:in
253 Beiträge seit 2006
vor 14 Jahren
double.Parse mit InvariantCulture liefert unerwarteten Wert

Hallo Forum,

ich zweifle gerade ob fxcop mir das leben leichter oder schwerer machen soll.
Folgendes Beispiel an einem Produktpreis von 2,00Euro erklärt:


double price = double.parse(sqlReader["price"].toString(), CultureInfo.InvariantCulture);

Mit diesem Code erhalte ich den Preis aus der Datenbank. Dank InvariantCulture erwarte ich eigentlich 2.0 oder 2 aber nicht 200. Ich könnte zwar nun InvariantCulture wieder entfernen aber dann meckert fxcop wieder. ?( 🙁

Wie löst ihr solche Formatierungen?

T
433 Beiträge seit 2006
vor 14 Jahren

Hi,

naja du solltest dir noch einmal Double.Parse anschauen. Es erwartet einen double als string der bei dir InvariantCulture sein sollte. 2,00 ist aber deutsch und nicht invariant.
Eine Lösung wäre es SqlDataReader.GetDouble zu verwenden, oder halt den richtigen FormatProvider anzugeben.

Btw würde ich für monetäre Variablen decimal als Datentyp verwenden.

Gruß,
Tom

J
3.331 Beiträge seit 2006
vor 14 Jahren

Hallo,

ToString ist in diesem Fall sowieso ein unnötiger/unsinniger Umweg: Du weißt, dass sqlReader["price"] einen double-Wert enthält. Also genügt ein einfacher cast:

double price = (double)sqlReader["price"];

Aber Tom hat recht: GetDouble ist der sichere Weg und decimal vermutlich besser.

Gruß Jürgen

T
tequila slammer Themenstarter:in
253 Beiträge seit 2006
vor 14 Jahren

Hallo Tom,

ich stimme dir zu, dass decimal hier sicherlich die besser Variante ist. Ich kenne auch die GetDouble Methode des readers allerdings müsste ich dann immer die Feldposition wissen. Was mich stutzig macht ist einfach die Tatsache, das aus 2.0 mit InvariantCulture 200 wird. Laut MSDN ist InvariantCulture mit Englisch zu vergleichen und daher sollte das ganze nach meinem Verständnis nicht passieren.

Vielleicht habe ich aber auch den Verwendungszweck von InvariantCulture nicht verstanden?

Gruß Sebastian

C
252 Beiträge seit 2007
vor 14 Jahren

Das Ganze ist von den verwendeten Regions-und Sprachoptionen des OS abhängig.
Vermutlich hast du bei dir Deutsch eingestellt, deshalb kann er den wert nicht mit invariant parsen. Da das Dezimalzeichen ein ',' ist. Invariant erwartet einen '.' als dezimaltrenner. Deshalb wird auch 200 draus.
Wenn du schon deine Variante verwendest dann must du beim toString() auch CultureInfo.InvariantCulture angeben. dann klappt das Parsen.

T
tequila slammer Themenstarter:in
253 Beiträge seit 2006
vor 14 Jahren

Hallo chavez,

genau das mache ich doch. Siehe obrigen Code. Deine Erklärung klingt logisch - würde aber doch bedeuten, das InvariantCulture mit vorsicht zu benutzen ist, dass die Werte durchaus verfälscht werden können.

T
433 Beiträge seit 2006
vor 14 Jahren

Hallo tequila,

ja natürlich kann es passieren das beim konvertieren von Daten Werte verfälscht werden können. Deshalb muss man da ganz genau wissen was rein geht und was hinten raus kommen soll.

Und wie gesagt wenn du bei Parse InvariantCulture angibst, geht er davon aus das dein string der rein geht invariant ist und das müsstest du sicherstellen.

Solltest du nur den Namen der Spalte kennen, kannst du auch SqlDataReader.GetOrdinal nutzen um den Index für SqlDataReader.GetDouble zu bekommen.

Gruß,
Tom

C
252 Beiträge seit 2007
vor 14 Jahren

genau das mache ich doch. Siehe obrigen Code.

Nö, das machst du eben beim toString() nicht, da verwendest du keine CultureInfo.
Folgendes sollte problemlos klappen:


double price = double.parse(sqlReader["price"].toString(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture);

Wie gesagt ist es beim toString() wichtig eine Cultureinfo anzugeben, da er sonst eben für die derzeit eingestellte Kultur üblich formatiert wird.

Ps: was mir durch Zufall vor kurzem aufgefallen ist. Die Schweizer verwenden ' für die Tausender-Gruppierung. Sieht etwas komisch aus meiner Meinung.

J
3.331 Beiträge seit 2006
vor 14 Jahren

Und am besten ist es (wie oben schon gesagt), auf den Quatsch mit ToString und dann zurück zu double ganz zu verzichten. Im sqlReader kommt ein double an; also nimm den doch. Jürgen

H
116 Beiträge seit 2008
vor 14 Jahren

(...) Ich kenne auch die GetDouble Methode des readers allerdings müsste ich dann immer die Feldposition wissen. (...)

public double getDouble(IDataRecord row, string fieldname)
{
    // TODO: NULL-Werte abfangen
    // TODO: row validieren
    // TODO: fieldname validieren
    double value = row.GetDouble(row.GetOrdinal(fieldname));
    return value;
}
T
tequila slammer Themenstarter:in
253 Beiträge seit 2006
vor 14 Jahren

Gut das es diese Forum gibt. Ich danke euch für die Hilfestellung - damit sollte ich weiterkommen. Danke noch mal an alle.