Decimal to string conversion issue - c#

Math.Round((ClosePrice - OpenPrice), 5) = -0.00001
But When I convert it into tostring it gives "-1E-05"
Math.Round((ClosePrice - OpenPrice), 5).ToString() = "-1E-05"
Why this is so ? How can I get "-0.00001"

You can use format specifier as demonstrated on MSDN's Standard Numeric Format Strings
double foo = -0.00001;
Console.WriteLine(foo.ToString("f5"));

ToString() chooses a format based on the value being formatted to achieve the most compact representation. If you would like to choose a specific format, you need to use the ToString(string format) overload instead. For example, if you call
Math.Round((ClosePrice - OpenPrice), 5).ToString("N5")
you will get "-0.00001" string as the result.

Every class inheriting from object (and therefore any class) has a .ToString() method. What it outputs depends on weather it was overwritten and if it was, how it was overwritten (i.e. what did the implementer want to give out as string. Its the same process you would go through if implementing a .ToString() method for one of your classes.
This is as to "Why" - the "How" has been answered by others.

Related

C# Convert int to string and use in a Label

I have the following scenario.I am using App.config in Winforms and I have a value that is set to int (In settings). I want to use this value as a label text.
Am I correct that labels can only display string values?
This is what I have done here but not getting expected result (value to the label):
int ExclRate = Properties.Settings.Default.PriorExclTimer;
string ExclTime = ExclRate.ToString();
ExclTime = label60.Text;
PriorExclTimer is the type of the value in app.config.
I can make this work if I set the value in app.config to string, but that means I would have to convert from string to int in a much more sensitive part of the program, and I would rather not have to do that if possible. This is that line that works:
label60.Text = Properties.Settings.Default.PriorExclTimer;
I'm very new to C#, so I am really feeling my way around. Thanks...
In C# you cannot directly assign int to string. It has to always undergo conversion (either parse string to integer, or get a string out of integer).
As you say it's better to convert integer to a string for display purposes. Labels cannot directly show integer, so you will always need to convert it, or write some wrapper class if it's not enough.
Be aware that ToString() is culture specific, i.e. it will use the culture from the current thread. It might or might not be what you want. If you want InvariantCulture you can use ToString(CultureInfo.InvariantCulture).
P.S. As mentioned in the comments you can do various tricks like ExclRate + "", or in C#6 ${ExclRate}, but they are all basically converting an integer to string. I guess they all call ToString() inside.
int ExclRate = Properties.Settings.Default.PriorExclTimer;
label60.Text = ExclRate.ToString();
Code above will give you exception if PriorExclTimer is null or empty. So better you use int.TryParse to assign it to int. Not in this case, but ToString does not handle the null case, it gives exception. So you should try Convert.ToString instead.
While doing string manipulations you have to take care of culture and case (string case sensitive or insensitive)
This works for me:
int ExclRate = Properties.Settings.Default.PriorExclTimer;
label60.Text = ExclRate.ToString();
Many thanks for the insights on this topic. I will be manipulating data to and from a string a good bit for the project I am working on...

String to Double Conversion (Comma to dot issue)

Struggling with the basics - I'm trying to code a simple currency converter. The XML provided by external source uses comma as a decimal separator for exchange rate (kurs_sredni):
<pozycja>
<nazwa_waluty>bat (Tajlandia)</nazwa_waluty>
<przelicznik>1</przelicznik>
<kod_waluty>THB</kod_waluty>
<kurs_sredni>0,1099</kurs_sredni>
</pozycja>
I already managed to load the data from XML into a nifty list of objects (kursyAktualne), and now i'm trying to do the math. I'm stuck with conversion.
First of all i'm assigning "kurs_sredni" to a string, trying to replace "," with "." and converting the hell out of it:
string kursS = kursyAktualne[iNa].kurs_sredni;
kursS.Replace(",",".");
kurs = Convert.ToDouble(kursS);
MessageBox.Show(kurs.ToString());
The messagebox show 1099 instead of expected 0.1099 and kursS still has comma, not dot.
Tried toying with some cultureInfo stuff i googled, but that was too random. I need to understand how to control this.
Just use decimal.Parse but specify a CultureInfo. There's nothing "random" about it - pick an appropriate CultureInfo, and then use that. For example:
using System;
using System.Globalization;
class Test
{
static void Main()
{
var french = CultureInfo.GetCultureInfo("fr-FR");
decimal value = decimal.Parse("0,1099", french);
Console.WriteLine(value.ToString(CultureInfo.InvariantCulture)); // 0.1099
}
}
This is just using French as one example of a culture which uses , as a decimal separator. It would probably make sense to use the culture of the origin of the data.
Note that decimal is a better pick for currency values than double - you're trying to represent an "artificial" construct which is naturally specified in base10, rather than a "natural" continuous value such as a weight.
(I would also be wary of a data provider who provides data in a non-standard format. If they're getting that wrong, who knows what else they'll get wrong. It's not like XML doesn't have a well-specified format for numbers...)
It is because Replace method returns new string with replaced characters. It does not modify your original string.
So you need to reassign it:
kursS = kursS.Replace(",",".");
Replace returns a string. So you need an assignment.
kursS = kursS.Replace(",", ".");
There is "neater" way of doing this by using CulturInfo. Look this up on the MSDN website.
You replace result isn't used, but the original value that doesn't contain the replace.
You should do:
kursS = kursS.Replace(",", ".")
In addition this method isn't really safe if there are thousands-separators.
So if you are not using culture settings you should do:
kursS = kursS.Replace(".", "").Replace(",", ".")

Strange behaviour of String.Format when (mis-)using placeholders

When I learned about the String.Format function, I did the mistake to think that it's acceptable to name the placeholders after the colon, so I wrote code like this:
String.Format("A message: '{0:message}'", "My message");
//output: "A message: 'My message'"
I just realized that the string behind the colon is used to define the format of the placeholder and may not be used to add a comment as I did.
But apparently, the string behind the colon is used for the placeholder if:
I want to fill the placeholder with an integer and
I use an unrecognized formating-string behind the colon
But this doesn't explain to me, why the string behind the colon is used for the placeholder if I provide an integer.
Some examples:
//Works for strings
String.Format("My number is {0:number}!", "10")
//output: "My number is 10!"
//Works without formating-string
String.Format("My number is {0}!", 10)
//output: "My number is 10!"
//Works with recognized formating string
String.Format("My number is {0:d}!", 10)
//output: "My number is 10!"
//Does not work with unrecognized formating string
String.Format("My number is {0:number}!", 10)
//output: "My number is number!"
Why is there a difference between the handling of strings and integers? And why is the fallback to output the formating string instead of the given value?
Just review the MSDN page about composite formatting for clarity.
A basic synopsis, the format item syntax is:
{ index[,alignment][:formatString]}
So what appears after the : colon is the formatString. Look at the "Format String Component" section of the MSDN page for what kind of format strings are predefined. You will not see System.String mentioned in that list. Which is no great surprise, a string is already "formatted" and will only ever appear in the output as-is.
Composite formatting is pretty lenient to mistakes, it won't throw an exception when you specify an illegal format string. That the one you used isn't legal is already pretty evident from the output you get. And most of all, the scheme is extensible. You can actually make a :message format string legal, a class can implement the ICustomFormatter interface to implement its own custom formatting. Which of course isn't going to happen on System.String, you cannot modify that class.
So this works as expected. If you don't get the output you expected then this is pretty easy to debug, you've just go two mistakes to consider. The debugger eliminates one (wrong argument), your eyes eliminates the other.
String.Format article on MSDN has following description:
A format item has this syntax: { index[,alignment][ :formatString] }
...
formatString Optional.
A string that specifies the format of the
corresponding argument's result string. If you omit formatString, the
corresponding argument's parameterless ToString method is called to
produce its string representation. If you specify formatString, the
argument referenced by the format item must implement the IFormattable
interface.
If we directly format the value using the IFormattable we will have the same result:
String garbageFormatted = (10 as IFormattable).ToString("garbage in place of int",
CultureInfo.CurrentCulture.NumberFormat);
Console.WriteLine(garbageFormatted); // Writes the "garbage in place of int"
So it seems that it is something close to the "garbage in, garbage out" problem in the implementation of the IFormattable interface on Int32 type(and possibly on other types as well). The String class does not implement IFormattable, so any format specifier is left unused and .ToString(IFormatProvider) is called instead.
Also:
Ildasm shows that Int32.ToString(String, INumberFormat) internally calls
string System.Number::FormatInt32(int32,
string,
class System.Globalization.NumberFormatInfo)
But it is the internalcall method (extern implemented somewhere in native code), so Ildasm is of no use if we want to determine the source of the problem.
EDIT - CULPRIT:
After reading the How to see code of method which marked as MethodImplOptions.InternalCall? I've used the source code from Shared Source Common Language Infrastructure 2.0 Release (it is .NET 2.0 but nonetheless) in attempt to find a culprit.
Code for the Number.FormatInt32 is located in the ...\sscli20\clr\src\vm\comnumber.cpp file.
The culprit could be deduced from the default section of the format switch statement of the FCIMPL3(Object*, COMNumber::FormatInt32, INT32 value, StringObject* formatUNSAFE, NumberFormatInfo* numfmtUNSAFE):
default:
NUMBER number;
Int32ToNumber(value, &number);
if (fmt != 0) {
gc.refRetString = NumberToString(&number, fmt, digits, gc.refNumFmt);
break;
}
gc.refRetString = NumberToStringFormat(&number, gc.refFormat, gc.refNumFmt);
break;
The fmt var is 0, so the NumberToStringFormat(&number, gc.refFormat, gc.refNumFmt); is being called.
It leads us to nothing else than to the second switch statement default section in the NumberToStringFormat method, that is located in the loop that enumerates every format string character. It is very simple:
default:
*dst++ = ch;
It just plain copies every character from the format string into the output array, that's how the format string ends repeated in the output.
From one point of view it allows to really use garbage format strings that will output nothing useful, but from other point of view it will allow you to use something like:
String garbageFormatted = (1234 as IFormattable).ToString("0 thousands and ### in thousand",
CultureInfo.CurrentCulture.NumberFormat);
Console.WriteLine(garbageFormatted);
// Writes the "1 thousands and 234 in thousand"
that can be handy in some situations.
Interesting behavior indeed BUT NOT unaccounted for.
Your last example works when
if String.Format("My number is {0:n}!", 10)
but revert to the observed beahvior when
if String.Format("My number is {0:nu}!", 10)`.
This prompts to search about the Standard Numeric Format Specifier article on MSDN where you can read
Standard numeric format strings are used to format common numeric
types. A standard numeric format string takes the form Axx, where:
A is a single alphabetic character called the format specifier. Any
numeric format string that contains more than one alphabetic
character, including white space, is interpreted as a custom numeric
format string. For more information, see Custom Numeric Format
Strings.
The same article explains: if you have a SINGLE letter that is not recognized you get an exception.
Indeed
if String.Format("My number is {0:K}!", 10)`.
throws the FormatException as explained.
Now looking in the Custom Numeric Format Strings chapter you will find a table of eligible letters and their possible mixings, but at the end of the table you could read
Other
All other characters
The character is copied to the result string unchanged.
So I think that you have created a format string that cannot in any way print that number because there is no valid format specifier where the number 10 should be 'formatted'.
No it's not acceptable to place anything you like after the colon. Putting anything other than a recognized format specifier is likely to result in either an exception or unpredictable behaviour as you've demonstrated. I don't think you can expect string.Format to behave consistently when you're passing it arguments which are completely inconsistent with the documented formatting types

VB6 Format equivalent in C#

I am converting some VB6 code to C# and am having a problem duplicating certain functionality. I have a string representation of a number ex.6000 and a format specifier of ex. ###0.000.
VB6 Example:
Format(number, "########0.000") = "6.000"
I am having trouble finding the C# equivalent to duplicate this functionality. The methods I have tried with ToString() but they are more for formatting the actual number rather than more of an overlay format like VB6 is doing.
C# Example:
number.ToString("########0.000", CultureInfo.InvariantCulture) = 6000.000
Personally, I think you should simply revisit your inputs and numeric specifiers to be more appropriate, but: you could cheat with:
string s = number.ToString(#"########0\.000", CultureInfo.InvariantCulture)
The \. is now not the decimal point specifier, but a literal. Horrible horrible answer. Please don't do it.
you can use the "FormatNumber" function instead

state at compile time not known

I need a way to Parse an string into an integer value in c#. The problem is the user chosses a string from a combo box which contains strings such as "AAAAA" or "5". That means only at run time it is known if the parameter is a real string or an string which can be parsed to an integer. I tried around with reflection and have the fitting Parameter object.
ParameterInfo p = ps[i];
Type t = p.ParameterType;
I don't know how to go on from there or if it even is possible. I can't use if else statments because the program is supposed to load other interfaces with new parameters as well. So I could handle the default ones with if else statmentes but when a new interface with new Methodinfos is loaded that dos not work anymore.
I'm not usre that understood all your constraints. However you can parse string by using Int32.TryParse in case target string is not necessarily valid.
Int32.TryParse whould help you with that
To parse a string into an integer, you can use Convert.ToInt32(string_var), or any of the other conversion methods. See here for more.

Categories