Pregunta

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());
¿Fue útil?

Solución

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.

Otros consejos

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.

See Implicit Numeric Conversions Table.

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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top