4

Could somebody explain me the following compiler issue

Error: Type of conditional expression cannot be determined because there is no implicit conversion between 'string' and 'int'

// WORKS
string text = string.Format(
    "the id is {0}", _Obj.Id.ToString());

// WORKS, without implicit conversion <<<
string text = string.Format(
    "the id is {0}", _Obj.Id);

// WORKS
string text = string.Format(
    "the id is {0}", (_Obj == null) ? "unknown" : _Obj.Id.ToString());

// NO WAY <<<
string text = string.Format(
    "the id is {0}", (_Obj == null) ? "unknown" : _Obj.Id);

in the last example, there is no implicit conversion, as well.

1
  • Nope................:0 Sorry. See my answer below... Commented Nov 15, 2010 at 11:43

8 Answers 8

9

The problem is nothing to do with your usage of string.Format. The problem is this expression:

(_Obj == null) ? "unknown" : _Obj.Id

The compiler cannot determine the type of this expression because there is no implicit conversion between int and string. You have already found the solution - calling ToString means that the expression returns a string in either case. Another way you could have fixed it (but slightly less efficient in this case because of boxing) is to tell the compiler explicitly how to perform the conversion. For example, you can use an explicit cast to object:

(_Obj == null) ? "unknown" : (object)_Obj.Id

Your second example works without an explicit cast because string.Format expects an object and there is an implicit conversion from int to object.

Sign up to request clarification or add additional context in comments.

4 Comments

I use often string.Format because it does not require me to use ToString(), it does implicitly. as String.Format accepts all type of argument, the compiler could box the result as Object.
@serhio: Without the ToString it would have to cast to object as that is the only common base class. The compiler won't do this for you automatically. In theory the compiler could always cast to object whenever y and z are incompatible in x ? y : z but then the code would always compile even in the cases where you made an error. The compiler is trying to warn you Hey, these objects are of different types, are you sure you want to do that? If you really want to you can still do it, but you need to say to the compiler Yes, I know what I'm doing, just cast to object - it will be fine.
I understand, however, this is not a warning, but an error. I'd prefeer that this be a warning, and evaluates me as "object"
@serhio: I think it's good that it's an error because when the only common base class is object it usually is an error. Why do you want it to be warning? Are you happy writing code that generates warnings? Isn't it better just to add the call to ToString() as you have done?
5

See Eric Lippert's blog article Cast operators do not obey the distributive law.

Comments

2

What is the type this expression evaluates to?

(_Obj == null) ? "unknown" : _Obj.Id

5 Comments

Just look at the expression. If the compiler can't tell which overload to use, it can't compile it.
@serhio: That is irrelevant. A conditional expression q ? x : y requires that x and y have compatible types. string and int are not compatible.
@Joren: What do you mean by "compatible"? both could be boxed to object.
Compatible with each other. Both are compatible with object, but that's not what the compiler cares about.
@Joren: "that's not what the compiler cares about". Why? It could.
1

I think you need to read this from MSDN: Conditional Operator.

Specially this part:

The second and third operands of the ?: operator control the type of the conditional expression. Let X and Y be the types of the second and third operands. Then,

If X and Y are the same type, then this is the type of the conditional expression. Otherwise, if an implicit conversion (Section 6.1) exists from X to Y, but not from Y to X, then Y is the type of the conditional expression. Otherwise, if an implicit conversion (Section 6.1) exists from Y to X, but not from X to Y, then X is the type of the conditional expression. Otherwise, no expression type can be determined, and a compile-time error occurs.

1 Comment

yes, but... I'd prefer: Otherwise, the the type of conditional expression is object :)
0
"the id is {0}", (_Obj == null) ? "unknown" : _Obj.Id

compiler have to choose either pick string type or integer (guess) which is not can be exchanged vice versa by default (without implicit conversion)

string text = string.Format("the id is {0}", _Obj.Id)

string.Format takes object as arg, so no problem to convert Id (integer) to object.

Comments

0

The last one works because string.format will accept (string, object).

The first will not work because the ? : operator needs matching types.

2 Comments

I believe this restriction is not necessary. Apparently Microsoft does not think like me :)
@serhio: It is not necessary. It's a design choice. The benefit of requiring that the operands of the conditional operator unambiguously determine the type is that difficult and costly problems with code analysis are eliminated. The drawback is that the user must ensure that the operator has a consistently inferrable type that does not depend on the context of the expression. Design choices are always the result of finding the compromise that balances conflicting priorities.
0

the problem is that

// WORKS, without implicit conversion 
string text = string.Format( 
    "the id is {0}", _Obj.Id); 

and

// NO WAY 
string text = string.Format( 
    "the id is {0}", (_Obj == null) ? "unknown" : _Obj.Id); 

are NOT the same!

Try to think the term

(_Obj == null) ? "unknown" : _Obj.Id);

as

function int Eval(object obj)
{
  if (obj == null)
  {
    return "unknown";
  }
  else
  {
    return "1";
  }
}

Which obviously is not working. So the whole thing has nothing to do with string.format.

1 Comment

function object Eval(object obj)
-1

in the first case (that does not work) if _Obj == null, you return a string, else your return an int. That of course causes a problem, since you in that case try to assign an int to string text.

3 Comments

Afraid that's incorrect - the issue is that the conditional expression must resolve to a single type, not two different types. Has nothing to do with the output of String.Format being assigned to string text.
Last example is about string.Format and has nothing to do with the ?: operator. Just because ?: specifies that both parameters must be the same type, or types that has an implicit conversion between them, does not mean that string.Format should fail for the same reason. string.Format returns a string regardless of the parameters, and assigning the result to string text is therefore unproblematic. In the ?: case, you return either a string or an int, and assigning that to string text will of course generate a compiler exception.
@sgreeve - And I never claimed it to either. I explained why the ?: case (first case) failed, not why the last case didn't

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.