Which is faster, Convert.ToXX() or xx.Parse(yy.ToString())? - c#

I'm trying to make a method faster. Right now, it takes an object obj and converts it to a double with the following:
double val = Convert.ToDouble(obj);
Would it be faster if I did this?
double val = double.Parse(obj.ToString());

For string Convert.ToDouble just checks value for null and return 0.0 if so. Then it really calls double.Parse:
[__DynamicallyInvokable]
public static double ToDouble(object value)
{
if (value != null)
return ((IConvertible) value).ToDouble((IFormatProvider) null);
else
return 0.0;
}
// common implementation of IConvertable
double IConvertible.ToDouble(IFormatProvider provider)
{
return Convert.ToDouble(this, provider);
}
// implementation for string
[__DynamicallyInvokable]
public static double ToDouble(string value, IFormatProvider provider)
{
if (value == null)
return 0.0;
else
return double.Parse(value, NumberStyles.Float | NumberStyles.AllowThousands, provider);
}
// and for long. differs, right?
[__DynamicallyInvokable]
public static double ToDouble(long value)
{
return (double) value;
}
So I don't think that double.Parse if much faster for non-number types. But when you don't really know that type your argument is, it's better to call Convert.ToDouble(value) instead of double.Parse(value.ToString()).

Convert.ToDouble() actually wraps a double.Parse() call so the difference in speed is negligible.

In theory the first, as you're making a single call. The second example you're calling the Parse method and then passing it the result of the ToString method.
That being said, see some of the comments as to why there maybe better solutions (i.e. what if it fails).

Related

Converter doesn't convert culture number format?

I have a string number in my C# program, it's "6.967.015". That's the german number format where "." seperates the 1000-groups and "," is the decimal seperator.
I made a function that uses Double.TryParse to convert the text to a double value. It works fine:
if (Double.TryParse(text, out result))
{
return result;
}
else
{
return defaultValue;
}
Now I needed a second type to be convertable and instead of copying the function, I wanted to make a function that accepts the type (don't mind the Type argument instead of generic <T> function, it's for integrity reasons).
public static object DefaultIfNotValid(this object value, Type type, object defaultValue)
{
var converter = TypeDescriptor.GetConverter(type);
object convertedValue;
if (converter != null)
{
try
{
convertedValue = converter.ConvertFrom(value);
return convertedValue;
}
catch (Exception)
{
return defaultValue;
}
}
return defaultValue;
}
The problem with this code is that it works for "123" but it doesn't work for the above number "6.967.015". The Convert function throws "6.967.015 is not a valid value for double". I tried giving the function a culture parameter to see if that was the problem, but that didn't work either (I passed null for the TypeDescriptorContext).
converter.ConvertFrom(null, new CultureInfo("de-de"), value);
That still threw the same exception. I also tried a custom culture with explicitly set group and decimal seperator, but still the same issue.
Maybe it's not even the culture but something else that the converter doesn't like about the value.
Does anyone know what could be the cause of this? Even though the string converts just fine with an explicit double.TryParse call.
You can try like this:
var nf = new NumberFormatInfo{NumberDecimalSeparator = ",", NumberGroupSeparator = "."};
var convertedValue = Convert.ToDouble(value, nf);
If TryParse method works use "method overload", default value for failed converting will be target type indicator in your case
Create own converting method for every type you want to convert
public static double DefaultIfNotValid(this string value, double defaultValue)
{
double temp = 0;
if (double.TryParse(value, out temp) == true)
return temp;
return defaultValue;
}
public static int DefaultIfNotValid(this string value, int defaultValue)
{
int temp = 0;
if (int.TryParse(value, out temp) == true)
return temp;
return defaultValue;
}
Then using seems not so painful
string rawValue = "6.967.015";
double defaultValue = 9.9;
double parsedValue = rawValue.DefaultIfNotValid(defaultValue);

How to check whether a (generic) number type is an integral or nonintegral type in C#?

I've got a generic type T. Using Marc's Operator class I can perform calculations on it.
Is it possible to detect by mere calculations whether the type is an integral or a nonintegral type?
Perhaps there is a better solution? I'd prefer to support any possible type, so I'd like to prevent hard-coding which types are integral/nonintegral.
Background info
The situation I find myself in is I want to cast a double to T but round to the nearest value of T to the double value.
int a = (int)2.6 results in 2 while I want it to result it in 3, without knowing the type (in this case int). It could also be double, in which case I want the outcome to be 2.6.
Have you tried Convert.ChangeType? Something like:
Convert.ChangeType(1.9d, typeof (T))
It will work for all numeric types I think (as long as the first parameter is iConvertible and the type is a supported one which all basic numerics should be I believe).
Its important to mention that this will call something like double.ToInt32 which rounds values rather than truncates (bankers rounding I believe).
I tested this in a little LinqPad program and it does what I think you want:
void Main()
{
var foo = RetNum<decimal>();
foo.Dump();
}
public static T RetNum<T>()
{
return (T)Convert.ChangeType(1.9d, typeof (T));
}
Here's a method which will determine if a particular value stored in a generic numeric type is an integer without hardcoding. Tested working for me on .NET 4. Correctly handles all built in numeric types (as defined in the MSDN link at the bottom) except BigInteger, which doesn't implement IConvertible.
public static bool? IsInteger<T>(T testNumber) where T : IConvertible
{
// returns null if T is non-numeric
bool? isInt = null;
try
{
isInt = testNumber.ToUInt64(CultureInfo.InvariantCulture) == testNumber.ToDouble(CultureInfo.InvariantCulture);
}
catch (OverflowException)
{
// casting a negative int will cause this exception
try
{
isInt = testNumber.ToInt64(CultureInfo.InvariantCulture) == testNumber.ToDouble(CultureInfo.InvariantCulture);
}
catch
{
// throw depending on desired behavior
}
}
catch
{
// throw depending on desired behavior
}
return isInt;
}
Here's a method which will determine whether a particular type is an integral type.
public static bool? IsIntegerType<T>() where T : IConvertible
{
bool? isInt = null;
try
{
isInt = Math.Round((double)Convert.ChangeType((T)Convert.ChangeType(0.1d, typeof(T)),typeof(double)), 1) != .1d;
// if you don't round it and T is float you'll get the wrong result
}
catch
{
// T is a non numeric type, or something went wrong with the activator
}
return isInt;
}
Convert.ChangeType is the way to convert, with rounding, between two generic numeric types. But for kicks and curiosity, here's a way to convert a generic numeric type to an int, which could be extended to return a generic type without too much difficulty.
public static int GetInt32<T>(T target) where T : IConvertible
{
bool? isInt = IsInteger<T>(target);
if (isInt == null) throw new ArgumentException(); // put an appropriate message in
else if (isInt == true)
{
try
{
int i = target.ToInt32(CultureInfo.InvariantCulture);
return i;
}
catch
{ // exceeded size of int32
throw new OverflowException(); // put an appropriate message in
}
}
else
{
try
{
double d = target.ToDouble(CultureInfo.InvariantCulture);
return (int)Math.Round(d);
}
catch
{ // exceeded size of int32
throw new OverflowException(); // put an appropriate message in
}
}
}
My results:
double d = 1.9;
byte b = 1;
sbyte sb = 1;
float f = 2.0f;
short s = 1;
int i = -3;
UInt16 ui = 44;
ulong ul = ulong.MaxValue;
bool? dd = IsInteger<double>(d); // false
bool? dt = IsInteger<DateTime>(DateTime.Now); // null
bool? db = IsInteger<byte>(b); // true
bool? dsb = IsInteger<sbyte>(sb); // true
bool? df = IsInteger<float>(f); // true
bool? ds = IsInteger<short>(s); // true
bool? di = IsInteger<int>(i); // true
bool? dui = IsInteger<UInt16>(ui); // true
bool? dul = IsInteger<ulong>(ul); // true
int converted = GetInt32<double>(d); // coverted==2
bool? isd = IsIntegerType<double>(); // false
bool? isi = IsIntegerType<int>(); // true
Additionally, this MSDN page has some example code which might be helpful. Specifically, it includes a list of types considered to be numeric.
I'm not 100% sure what you're asking, but:
To check if it's an integral type, use this: if (obj is float || obj is double), or if typeof(T) == typeof(float) || typeof(T) == typeof(double))
To check if it's an integral value, cast it to a double, and then do if(value == Math.Round(value))
Of course, that is assuming that you have a number in the first place. I believe that the Operator class you're using supports things like DateTime. Would it be better to make your generic method have a generic constraint where T : IConvertible? That way there'd be explicit ToDouble and ToInteger methods.
Edit:
I think I understand: you've got two local variables, double d; T num;. You want to cast d to type T, but with proper rounding if T is a integral type. Is that correct?
Assuming that's correct, here's what I'd do:
public void SomeMethod<T>()
{
double d;
// I think I got all the floating-point types. There's only a few, so we can test for them explicitly.
if(typeof(T) != typeof(double) && typeof(T) != typeof(float) && typeof(T) != typeof(Decimal))
{
d = Math.Round(d);
}
T converted = Convert.ChangeType(d, typeof(T));
}
Chris's answer gives a possible solution to the scenario I mentioned, but for performance reasons I am still attempting to answer the actual question.
The assumption (untested) is, Convert.ChangeType is much slower than Math.Round(). Ideally, I can check one time whether the given type is integral or not, and conditionally call Math.Round() from then on to obtain a much more efficient solution than calling Convert.ChangeType() constantly.
I'm attempting the following implementation:
Convert both 3, 2 and 1 to the desired unknown type. (This assumes a conversion from an int to the numeric type is possible, which should always be possible anyhow.)
In case 3 / 2 == 1, it is an integral type. Otherwise, it is a nonintegral type.
This solution doesn't rely anywhere on knowing the type and solely uses conversions and calculations.

How to call a function based on string value in C#

I want to convert a string to specific type based on the value of other string
Suppose I have two strings str1, str2.
If str2 is double then I want to call convert.ToDouble(str1) and return the Double value. Is there any way to accomplish this?
I tried using reflections (using methodInfo object to invoke)
But still it returns again an object for which I need to convert.
Please help..
Use the double.TryParse Method.
The method attempts to convert a string to a double and if it fails it returns false.
If I'm understanding you correctly, this is what you want:
private static double ConditionalConvertToDouble(string str1, string str2) {
double converted;
if (double.TryParse(str2, out converted)) {
// str2 can be converted to a double, so return str1 converted to a double.
return Convert.ToDouble(str1);
} else {
// I'm throwing an exception here if str1 cannot be converted to a double; you
// might want to do something different.
throw new ArgumentException("str1 cannot be converted to a double");
}
}
Call the method like this:
var d = ConditionalConvertToDouble("11", "22");
double result;
Double.TryParse(str1, out result);
if str1 is double, result will have its value, otherwise result will have 0. It will not throw any exception.
Hope it helps.
The following method will attempt to get the double value from "str1" if and only if "str2" also represents a double. If either of the numbers are not doubles, it will return double.NaN.
This method avoids throwing exceptions, but still allows you to check if you have a valid number.
public double GetFirstDoubleIfSecond(string str1, string str2)
{
double myDouble;
if(double.TryParse(str2, out myVal) && double.TryParse(str1, out myVal))
{
return myDouble
}
return double.NaN;
}
If you are expecting NaN values in your string, then you can use the following method, which will throw an exception if either of the strings are not doubles. Otherwise, it will return the string value represented in "str1".
public double GetFirstDoubleIfSecondWithExceptions(string str1, string str2)
{
double.Parse(str2);
return double.Parse(str1);
}
I think that switch-case operator should help to you. You should to specify some cases depending on one of your input string and make right decision. Your method should return object, if you really don't know which type exactly will return your method.
public object MyMethod(string str1, string str2)
{
switch(something)
{
case 1:
case 2:
return double.Parse(str1);
break;
case 3:
case 4:
return int.Parse(str1);
break;
default
return null;
}
}
where something is the criterion you should to specify.
After that System.Object.GetType() method can help you to detirmine which type was returned by your method.

Differences between int.Parse() and ConvertTo.Int32()? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicates:
difference between Convert.ToInt32 and (int)
Whats the main difference between int.Parse() and Convert.ToInt32
C#
Are there any differences between the type.Parse() methods and the methods at ConvertTo class?
No there is no substantial difference between Int32.Parse and Convert.ToInt32(string). The latter just forwards it's call to Int32.Parse
One minor difference though is that if you pass null to Convert.ToInt32 it will return 0, while Int32.Parse will through an ArgumentNullException
One notable difference is TypeConverter.ConvertTo(object) doesn't throw an exception when object is null, but type.parse does throws an exception when its contents are null
Most Important Difference is:
-Convert.ToInt32(s) doesn't throw an exception when s is null, but Parse()
does
If you're collecting input from a
user, you'd generally user
Int32.TryParse()
Int32.Parse() and Int32.TryParse()
can only convert strings.
Convert.ToInt32() can take any class
that implements IConvertible.
Basically in all truth, When you look
at the source from TryParse it
actually has no exception handling at
all - just character manipulation and
bit shifting
For Performance details, read this
post:
http://blogs.msdn.com/b/ianhu/archive/2005/12/19/505702.aspx
There are some differences, e.g. Convert can convert to Int32 from many objects (Int16, string, SByte, etc.). Also, Int32.Parse can accept NumberStyles, which Convert.ToInt32 cannot.
Other than that, Reflector (http://reflector.red-gate.com) has this to say:
class Convert:
public static int ToInt32(string value)
{
if (value == null)
{
return 0;
}
return int.Parse(value, CultureInfo.CurrentCulture);
}
AFAIK, int.Parse() is inherited from the Number class, where it's defined. Convert.ToIn32() implements the IConvertable interface and gets the type of the object you pass before handling the conversion.
Either way I think it ends up at Int32.Parse anyway.
Here's the code retrieved using Reflector.
Int32.Parse:
public static int Parse(string s)
{
return Number.ParseInt32(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
}
internal static unsafe int ParseInt32(string s, NumberStyles style,
NumberFormatInfo info)
{
byte* stackBuffer = stackalloc byte[1 * 0x72];
NumberBuffer number = new NumberBuffer(stackBuffer);
int num = 0;
StringToNumber(s, style, ref number, info, false);
if ((style & NumberStyles.AllowHexSpecifier) != NumberStyles.None)
{
if (!HexNumberToInt32(ref number, ref num))
{
throw new OverflowException(Environment.GetResourceString("Overflow_Int32"));
}
return num;
}
if (!NumberToInt32(ref number, ref num))
{
throw new OverflowException(Environment.GetResourceString("Overflow_Int32"));
}
return num;
}
Convert.ToInt32:
public static int ToInt32(string value)
{
if (value == null)
{
return 0;
}
return int.Parse(value, CultureInfo.CurrentCulture);
}
So, Convert anyway calls methods of Int32. Using of Int32.Parse will be more efficiently, but you need take into account that it can throw exception on passing null argument.
Converting or direct casting can cause data loss. You should consider making use of "is" and "as" over casting or converting. In addition to protection against data loss, these are both more efficient at runtime.
As Austin stated, if you are going to parse, use tryparse and handle failures accordingly.

How Can I Compare Any Numeric Type To Zero In C#

I would like to create a function that checks if a numeric value passed as an argument has a value greater than zero. Something like this:
public bool IsGreaterThanZero(object value)
{
if(value is int)
{
return ((int)value > 0);
}
else if(value is float)
{
// Similar code for float
}
return false;
}
Can I try to cast the object passed as the function's argument to one numeric data type so I can then compare it to zero rather than checking for each type in my if statement? If the cast fails I would return false. Is there a better(read shorter, more readable) way to do this?
Edit:
Some have asked about if I know the type will be a numeric, why the object etc. I hope this makes things clearer.
This function would be part of a Silverlight converter that implements the IValueConverter interface which has a convert signature of
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
A first, I only wanted the converter to work with ints but my imagination started to run wild and think what if I have floating point numbers and other numeric types. I wanted to make the converter as flexible as possible. Initially I thought all this extra information would get in the way of what I wanted to do so I didn't include it in my question.
Does the caller know the type? If so, how about:
public static bool GreaterThanZero<T>(T value) where T : struct, IComparable<T>
{
return value.CompareTo(default(T)) > 0;
}
No conversions needed, and should work for any of the built-in numeric types - and any sensible value types you come up with yourself. (For example, this would be fine with Noda Time's Duration struct.)
Note that the caller doesn't have to know the type directly - it may only know it as another type parameter with the same constraints. Admittedly this may not be appropriate for your situation, but I thought I'd mention it anyway. If nothing knows the type at compile-time (and you don't fancy getting dynamic typing to do the job for you in C# 4!) then calling Convert.ToDouble is probably your best bet - just be aware that it may have problems for System.Numerics.BigInteger from .NET 4.0.
My preference would be:
public bool IsGreaterThanZero(object value)
{
if(value is IConvertible)
{
return Convert.ToDouble(value) > 0.0;
}
return false;
}
This will handle all IConvertible types safely (which includes all floating point and integer types in the framework, but also any custom types).
Eh? What numeric types do you care about?
public bool IsGreaterThanZero(double value)
{
return value > 0;
}
These all work ...
IsGreaterThanZero((int)2);
IsGreaterThanZero((long)2);
IsGreaterThanZero((double)2);
IsGreaterThanZero((float)2);
IsGreaterThanZero((byte)2);
IsGreaterThanZero((ulong)2);
You can avoid boxing and unboxing using generics:
Here's the definition of a function
class GenericComparation {
public static bool IsGreaterThanZero<T>(T value) where T : IComparable<T> {
// Console.WriteLine(value.GetType().Name)
return value.CompareTo(default(T)) > 0;
}
}
Usage:
Console.WriteLine(GenericComparation.IsGreaterThanZero(1));
Console.WriteLine(GenericComparation.IsGreaterThanZero(-1.1));
Console.WriteLine(GenericComparation.IsGreaterThanZero(Decimal.Zero));
Try:
double tempValue;
if(double.TryParse(value.ToString(), out tempValue)
{
return (tempValue > 0)
}
else
{
return false;
}
Why not just Convert.ToDouble or Convert.ToDecimal and then do the comparison? Seems like that would handle most types that someone might pass in.
This simplest and fastest way to compare any numeric type To zero is as follows:
public bool IsGreaterThanZero(object value)
{
if (value != null && value.GetType().IsValueType)
return System.Convert.ToDouble(value) > 0;
return false;
}

Categories

Resources