2010-11-15 154 views
4

有人能解释一下我下面的编译器问题C#? :运营商

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); 

在最后一个例子,不存在隐式转换,以及。

+0

没有................:0对不起。看到我的回答如下... – UpTheCreek 2010-11-15 11:43:09

回答

-1

在第一种情况下(即不起作用)如果_Obj == null,则返回string,否则返回int。这当然会导致一个问题,因为你在这种情况下尝试分配intstring text

+0

看到最后一个例子。 – serhio 2010-11-15 11:42:01

+0

害怕这是不正确的 - 问题是条件表达式必须解析为单一类型,而不是两种不同类型。与分配给字符串文本的String.Format的输出无关。 – razlebe 2010-11-15 11:48:42

+0

最后一个例子是关于string.Format,与?:操作符无关。只是因为?:指定两个参数必须是相同的类型,或者它们之间存在隐式转换的类型,并不意味着string.Format应该因为相同的原因而失败。因此string.Format返回一个字符串,而不管参数如何,并且将结果分配给字符串文本是没有问题的。在?:的情况下,您返回一个字符串或一个int,并将其分配给字符串文本当然会生成一个编译器异常。 – 2010-11-15 11:48:48

2

此表达式计算的类型是什么?

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

string.Format接受任何类型作为参数 – serhio 2010-11-15 11:43:47

+2

只需查看表达式即可。如果编译器无法确定要使用哪个超载,则无法编译它。 – 2010-11-15 11:44:41

+0

@serhio:这是无关紧要的。一个条件表达式'q? x:y'要求'x'和'y'具有兼容的类型。 'string'和'int'不兼容。 – Joren 2010-11-15 11:46:23

10

该问题与您使用string.Format无关。问题是这样的表达式:

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

编译器不能确定这个表达式的类型,因为有intstring之间没有隐式转换。您已经找到该解决方案 - 调用ToString意味着无论哪种情况,表达式都会返回string。你可以修复它的另一种方法(但在这种情况下,因为装箱而效率稍低)是告诉编译器明确指出如何执行转换。例如,你可以使用一个显式的object

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

你的第二个例子工程没有进行明确的转换,因为string.Format期望一个object并且有一个隐式转换从intobject

+0

我经常使用string.Format,因为它不需要我使用ToString(),它会隐式地执行。作为String.Format接受所有类型的参数,**编译器可以将结果框为Object **。 – serhio 2010-11-15 11:47:19

+3

@serhio:如果没有'ToString',它必须转换为对象,因为这是唯一的公共基类。编译器不会自动为你做这件事。理论上,只要y和z在'x?中不兼容,编译器就可以转换为对象。 y:z',但即使在发生错误的情况下,代码也会始终编译。编译器试图警告你*嘿,这些对象是不同类型的,你确定要这样做吗?*如果你真的想要你仍然可以这样做,但你需要对编译器说*是的,我知道我在做什么,只是施展对象 - 这将是好的*。 – 2010-11-15 11:52:34

+0

但我明白,这不是一个警告,而是一个错误。我希望这是一个警告,并评估我为“对象” – serhio 2010-11-15 11:57:05

0
"the id is {0}", (_Obj == null) ? "unknown" : _Obj.Id 

编译器必须选择任一挑string型或integer(猜测)其是不是可以通过默认交换反之亦然(没有隐式转换)

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

string.Format需要object如精氨酸,所以没有问题将Id(整数)转换为对象。

0

最后一个工程,因为string.format将接受(string, object)

,因为? :运营商需要匹配的类型第一个将无法正常工作

+0

我相信这个限制是没有必要的。显然,微软并不认为像我:) – serhio 2010-11-15 11:59:00

+2

@serhio:它不*必要*。这是一个设计选择。要求条件运算符的操作数明确确定类型的好处是可以消除代码分析中的困难和代价高昂的问题。缺点是用户必须确保运算符具有不依赖表达式上下文的一致可推式类型。设计选择始终是找到平衡冲突优先事项的妥协方案的结果。 – 2010-11-15 18:03:33

1

我认为你需要阅读MSDN: Conditional Operator

专门这一部分:

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.

+0

是的,但...我宁愿:'否则,条件表达式的类型是** **对象** :) – serhio 2010-11-15 11:55:23

0

问题是

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

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

是不一样的!

试着想想术语

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

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

这显然是行不通的。所以整个事情与string.format无关。

+0

函数**对象** Eval(对象obj) – serhio 2010-11-15 11:50:33