Why does var get resolved as a Double and not Long?
Domanda
In the following code, I would expect var
to get resolved to an Int64
, but it gets resolved to a double
. Why is it so?
string a = "1234";
bool asInt = true;
var b = (asInt) ? Int64.Parse(a) : Double.Parse(a) ;
Console.WriteLine(b.GetType());
Soluzione
There is an implicit conversion from Int64
to Double
but not the other way (due to possible loss of precision in that direction).
Since both "branches" of the conditional need to resolve to the same type, the type of b
ends up being inferred as a Double
.
Altri suggerimenti
You can implicitly cast a long
to a double
.
You cannot implicitly cast a double
to a long
So the C# compiler decided the only possibility for your variable type was double
.
Because the compiler needs to infer a type that can hold values of both Int64.Parse(a)
and Double.Parse(a)
without requiring an explicit cast. If long
was inferred, precision would be lost in the other porsion of the expression.
If you need to distinguish the type, you have to declare two variables and rewrite your code:
if (asInt)
{
var b = Int64.Parse(a); // will infer a `long`
Console.WriteLine(b.GetType());
}
else
{
var b = Double.Parse(a); // will infer a `double`
Console.WriteLine(b.GetType());
}
The C# compiler is inferring the type from the common denominator between the two return types of your ternary. Int64 can be implicitly converted to Double. The inverse is not so.
Note that the state of the Boolean in your code example has nothing to do with the inferred type.
This is the work of ?:
operator. It should cast all results to one type.
P.S. The similar behavior of +
operator you know:
string a = "1234";
var b = Int64.Parse(a) + Double.Parse(a) ;
Console.WriteLine(b.GetType());
P.P.S. To have what you want you should use object
:
string a = "1234";
bool asInt = true;
object b;
if(asInt) b=Int64.Parse(a); else b=Double.Parse(a);
Console.WriteLine(b.GetType());
P.P.P.S. Another option is:
string a = "1234";
#if asInt
Int64 b = Int64.Parse(a);
#else
Double b = Double.Parse(a);
#endif
Console.WriteLine(b.GetType());
to define asInt use
#define asInt
I'm surprised nobody has pointed out that if you know the value will be a legal long
value, you can change the compiler's behavior with an explicit cast, and just use long
.
This may or may not be helpful, depending on the condition that determines the value for asInt
, and depending on what you intend to do with the result of the expression. Here's an example:
string a = "1234.56";
bool asDouble = a.Contains(".");
var b = asDouble ? (long)Double.Parse(a) : Int64.Parse(a);
Console.WriteLine(b.GetType());
In fact, in this example, you don't need the conditional operator; this would work too:
string a = "1234.56";
var b = (long)Double.Parse(a);
Console.WriteLine(b.GetType());
In other words, it's possible that the best solution wouldn't use the ternary operator, but the question doesn't give enough context to know.