I'm running a beta version of ReSharper, and it's giving me warnings for the following code:
int id;
// ...
DoSomethingWith(id.ToString());
The warning is on the id.ToString() call, and it's telling me "Specify a culture in string conversion explicitly". I understand the warning, and I know how to fix it -- just change the code to the much more unwieldy id.ToString(CultureInfo.InvariantCulture).
But my question is: is that necessary? I mean, obviously it's important to specify the culture when you're using types like DateTime (different cultures have different date formats) and Double (different characters used for the decimal point). But Int32.ToString(), at least in the en-US and invariant cultures, doesn't add any formatting at all. No commas, no decimal points, no dollar signs, nothing. So what would there be to vary by culture?
Are there some cultures that actually add some sort of formatting when you call the parameterless Int32.ToString()? Or is this a bug in the ReSharper beta, and this warning really isn't applicable to Int32 (in which case I'll file a ReSharper bug report)?
The Operating System allows to change the negative sign for numbers.
Control panel ->
Language and regional settings ->
Additional settings ->
Negative sign
So, current culture could have overridden the negative sign. In this case you need to respect the regional settings, this is the reason of the warning. You can also change the negative sign programatically:
CultureInfo culture = Thread.CurrentThread.CurrentCulture;
// Make a writable clone
culture = (CultureInfo) culture.Clone();
culture.NumberFormat.NegativeSign = "!";
As tested on a random sample of ints, all 352 cultures installed with Windows (CultureTypes.InstalledWin32Cultures) give identical results.
Daniel is right to note a custom culture could use a different prefix for negative numbers, but I doubt anyone has ever used this feature save by accident.
I guess the .NET devs did it to be consistent with float and other types. What else were they expecting?
> int.MaxValue.ToString(CultureInfo.AncientRome)
MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM....
It's weird; I would have expected 50.ToString(CultureInfo.CreateSpecificCulture("ar-AE")) to return "٥٠", but it doesn't.
I've just looked this up, and the problem seems to be that NumberFormatInfo.DigitSubstitution isn't actually implemented
The DigitSubstitution property is reserved for future use. Currently, it is not used in either parsing or formatting operations for the current NumberFormatInfo object.
So, although there is an enumeration System.Globalization.DigitShapes, it's not actually implemented in the NumberFormatInfo bit of IFormatProvider.
Yes. It depends on the current culture. From the MSDN docs:
The return value is formatted with the general numeric format specifier ("G") and the NumberFormatInfo object for the current culture.
emphasis mine
Resharper just most likely wants you to be explicit about what culture you are intending to use. Since omitting it relies on behavior that may change when executed on different machines.
The compiler is (unnecessarily) warning us about it COULD be casted to string somehow not as we expected it to be. For example:
int i = 1;
Console.WriteLine("i.ToString='{0}'", i.ToString());
We all expect it to return as '1' but it is not 100% guaranteed because .ToString() method gets affected by the current thread culture. It CLAIMS that it could return as '1.00' or something like that but I tested it with a really small code:
foreach(CultureInfo ci In System.Globalization.CultureInfo.GetCultures(CultureTypes.AllCultures) {
Console.WriteLine("RESULT='{0}' CultureCode: {1} EnglishName:{2}", i.ToString(ci), ci.Name, ci.EnglishName);
if (!i.ToString(ci).Equals("1"))
throw new FormatException()
}
The code never returned any error. So, it actually never returns anything other than "1".
As far as there will be a new country with a brand new native super-weirdo language in this world that actually spells "1.00" for an integer, we can keep using just .ToString() without any doubt.
Cheers!
Output was:
I would have said no, but on checking MSDN Int32.ToString() there's this:
The return value is formatted with the general numeric format specifier ("G") and the NumberFormatInfo object for the current culture.
So there's a surprise.
The question should be why doesn't the current Resharper suggest this?
Because integers can be be as high as 2,147,483,647.
In some countries, they would use decimals or a space in place of the commas.
Related
I've got a DataGridView that I'd like to apply formatting changes to based on cell values. I'd like to do it using the original DataTable source but unfortunately building the source required removing and reorienting certain rows so the indexes are off. As such, I'm trying to do it using
double.TryParse(DataGridView
.Rows[index]
.Cells["ColumnName"]
.FormattedValue.ToString(), out dbl);
however, it never recognizes the value as a double. I've verified the output using MessageBox'es and that there are no leading or trailing spaces that might cause issue by adding "-" to both sides of the MessageBox string. I'm clueless as to why it will always regard the value as not a double even on values that are clearly parseable as doubles.
Edit : I'm not sure what changed over the weekend but I came in, fixed a different bug unrelated to this and now the bold is working using .Value rather than .FormattedValue as suggested by gh0st below.
double.TryParse() will parse the string in a culture dependant way. It is very likely that your current culture expects the decimal point to be some other symbol, like the comma or something.
For instance, on my machine, I can force it to fail the parsing by passing a different culture, like this:
double.TryParse("1.2",
NumberStyles.Float | NumberStyles.AllowThousands,
CultureInfo.GetCultureInfo("fr-FR"),
out dbl); // returns false
If this is what is happening to you, then either you find a way to change the current culture, or perhaps you can do the parsing this way instead to ensure consistent results:
double.TryParse("1.2",
NumberStyles.Float | NumberStyles.AllowThousands,
CultureInfo.InvariantCulture,
out dbl); // returns true
(*) Note: the NumberStyles.Float | NumberStyles.AllowThousands values can be adjusted as you like. I just set it to that in this example, because that is the default that the TryParse method uses when using the overload with less parameters.
Basically I'm realizing that my application is using commas instead of decimals, and i NEVER want to allow this. Anyone know how I can correct? I can't find one thing via google that is to force decimals, it's all about forcing commas.
return String.Format("{0}f, {1}f, {2}f, {3}f, {4}f, {5}f, {6}f, {7}f, {8}f, {9}f, {10}f, {11}f, {12}f, {13}f, {14}f, {15}f", M.M11, M.M12, M.M13, M.M14, M.M21, M.M22, M.M23, M.M24, M.M31, M.M32, M.M33, M.M34, M.OffsetX, M.OffsetY, M.OffsetZ, M.M44);
You can use the other overload:
return String.Format(
CultureInfo.InvariantCulture // <<== That's the magic
, "{0}f, {1}f, {2}f, {3}f, {4}f, {5}f, {6}f, {7}f, {8}f, {9}f, {10}f, {11}f, {12}f, {13}f, {14}f, {15}f"
, M.M11, M.M12, M.M13, M.M14, M.M21, M.M22, M.M23, M.M24, M.M31, M.M32, M.M33, M.M34, M.OffsetX, M.OffsetY, M.OffsetZ, M.M44
);
This way of calling ensures that the invariant culture is being passed as the format provider to the String.Format, ensuring that you get dots for numbers, dollars for currency symbols, English for names of the months and days, and so on.
Try setting the culture to US English for the String.Format function:
String.Format(new CultureInfo("en-US"), "{0}f, {1}f, {2}f", etc)
Just something that i was wondering about.
In Europe the comma us mostly used for decimals (like 20,001) but outside Europe the point is mostly used (like 20.001)
How does c# handle this ?
In case of a application that will be used by Europe and non-Europe people, do you need to worry about the above when programming ?
Just curious about this.
As far as the programming language is concerned, the decimal point separator is always ., and the punctuation used to separate function arguments is always ,. Changing that based on the spoken language of the programmer would be too confusing.
For the user interface, there are formatting functions in the CultureInfo class that can produce a floating point number representation that uses the decimal point separator and thousands separator of your choice. (Or, for cultures that group digits of a number differently than in triplets, the formatting functions can handle that too.)
CultureInfo handles that situation.
Take a look at this
// format float to string
float num = 1.5f;
string str = num.ToString(CultureInfo.InvariantCulture.NumberFormat); // "1.5"
string str = num.ToString(CultureInfo.GetCultureInfo("de-DE").NumberFormat); // "1,5"
Yes, c# (and really, the whole .NET framework) have the concept of Cultures for this purpose:
http://msdn.microsoft.com/en-us/library/bz9tc508.aspx
and
http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo(v=VS.100).aspx
You should use CultureInfo Class to handle it. Just read and write with correct formatter.
That depends on what exactly you do... .NET is usually aware of the current settings of the machine/OS and uses those...
You should look into this and see whether any of it is relevant in your case...
I have a program that sometimes is used in locales that use commas for the decimal separator. Its nice how C# handles all that (good for the UI), but when I export to a file, I need to always use a ".", not the locale specific number. Currently, I do:
String.Format("{0:0.####},{1:0.####}", x, y)
Problem is that in some locales, that ends up using commas instead of periods. Question is, is there a format code that says "always use period", or is the only solution to mess with one's locale?
Simply use:
String.Format(CultureInfo.InvariantCulture, "{0:0.####},{1:0.####}", x, y)
I'd recommend trying FxCop (or the Code Analysis feature of the Team variants of VS2005+).
It generates a lot of noise (false positives), but does provide a lot of good practice.
Including: always use the overload that takes an IFormatProvider parameter if one is available - typically you will use CultureInfo.CurrentCulture for formatting output for the user, and CultureInfo.InvariantCulture for storing data in files, the registry etc.
What is the best way to parse a float in CSharp?
I know about TryParse, but what I'm particularly wondering about is dots, commas etc.
I'm having problems with my website. On my dev server, the ',' is for decimals, the '.' for separator. On the prod server though, it is the other way round.
How can I best capture this?
I agree with leppie's reply; to put that in terms of code:
string s = "123,456.789";
float f = float.Parse(s, CultureInfo.InvariantCulture);
Depends where the input is coming from.
If your input comes from the user, you should use the CultureInfo the user/page is using (Thread.CurrentThread.CurrentUICulture).
You can get and indication of the culture of the user, by looking at the HttpRequest.UserLanguages property. (Not correct 100%, but I've found it a very good first guess) With that information, you can set the Thread.CurrentThread.CurrentUICulture at the start of the page.
If your input comes from an internal source, you can use the InvariantCulture to parse the string.
The Parse method is somewhat easier to use, if your input is from a controlled source. That is, you have already validated the string. Parse throws a (slow) exception if its fails.
If the input is uncontrolled, (from the user, or other Internet source) the TryParse looks better to me.
If you want persist values ( numbers, date, time, etc... ) for internal purpose. Everytime use "InvariantCulture" for formating & parsing values. "InvariantCulture" is same on every computer, every OS with any user's culture/language/etc...
string strFloat = (15.789f).ToString(System.Globalization.CultureInfo.InvariantInfo);
float numFloat = float.Parse(System.Globalization.CultureInfo.InvariantInfo, strFloat);
string strNow = DateTime.Now.ToString(System.Globalization.CultureInfo.InvariantInfo);
DateTime now = DateTime.Parse(System.Globalization.CultureInfo.InvariantInfo, strNow);
You could always use the overload of Parse which includes the culture to use?
For instance:
double number = Double.Parse("42,22", new CultureInfo("nl-NL").NumberFormat); // dutch number formatting
If you have control over all your data, you should use "CultureInfo.InvariantCulture" in all of your code.
Use a neutral culture (or one you know) when parsing with Try/Parse.
Pass in a CultureInfo or NumberFormatInfo that represents the culture you want to parse the float as; this controls what characters are used for decimals, group separators, etc.
For example to ensure that the '.' character was treated as the decimal indicator you could pass in CultureInfo.InvariantCulture (this one is typically very useful in server applications where you tend to want things to be the same irrespective of the environment's culture).
Try to avoid float.Parse, use TryParse instead as it performs a lot better but does the same job.
this also applies to double, DateTime, etc...
(some types also offer TryParseExact which also performs even better!)
The source is an input from a website. I can't rely on it being valid. So I went with TryParse as mentioned before.
But I can't figure out how to give the currentCulture to it.
Also, this would give me the culture of the server it's currently running on, but since it's the world wide web, the user can be from anywhere...
you can know current Cuklture of your server with a simple statement:
System.Globalization.CultureInfo culture = System.Globalization.CultureInfo.CurrentCulture;
Note that there id a CurrentUICulture property, but UICulture is used from ResourceMeanager form multilanguages applications. for number formatting, you must considere CurrentCulture.
I hope this will help you
One approach is to force localization to use dot instead of comma separator - this way your code will work identically on all windows machines independently from selected language and settings.
This approach is applicable to small gained applications, like test applications, console applications and so on. For application, which was localization in use this is not so useful, but depends on requirements of application.
var CurrentCultureInfo = new CultureInfo("en", false);
CurrentCultureInfo.NumberFormat.NumberDecimalSeparator = ".";
CurrentCultureInfo.NumberFormat.CurrencyDecimalSeparator = ".";
Thread.CurrentThread.CurrentUICulture = CurrentCultureInfo;
Thread.CurrentThread.CurrentCulture = CurrentCultureInfo;
CultureInfo.DefaultThreadCurrentCulture = CurrentCultureInfo;
This code forces to use dot ('.') instead of comma, needs to be placed at application startup.
Since you don't know the web user's culture, you can do some guesswork. TryParse with a culture that uses , for separators and . for decimal, AND TryParse with a culture that uses . for separators and , for decimal. If they both succeed but yield different answers then you'll have to ask the user which they intended. Otherwise you can proceed normally, given your two equal results or one usable result or no usable result.