Lan*_*don 9 c# ternary-operator
失败:
object o = ((1==2) ? 1 : "test");
Run Code Online (Sandbox Code Playgroud)
成功:
object o;
if (1 == 2)
{
o = 1;
}
else
{
o = "test";
}
Run Code Online (Sandbox Code Playgroud)
第一个语句中的错误是:
无法确定条件表达式的类型,因为'int'和'string'之间没有隐式转换.
为什么需要这样,我将这些值分配给object类型的变量.
编辑:上面的例子是微不足道的,是的,但有一些例子,这将是非常有用的:
int? subscriptionID; // comes in as a parameter
EntityParameter p1 = new EntityParameter("SubscriptionID", DbType.Int32)
{
Value = ((subscriptionID == null) ? DBNull.Value : subscriptionID),
}
Run Code Online (Sandbox Code Playgroud)
Joh*_*zen 17
使用:
object o = ((1==2) ? (object)1 : "test");
Run Code Online (Sandbox Code Playgroud)
问题是条件运算符的返回类型不能无歧义地确定.也就是说,在int和string之间,没有最佳选择.编译器将始终使用true表达式的类型,并在必要时隐式转换false表达式.
编辑: 在你的第二个例子中:
int? subscriptionID; // comes in as a parameter
EntityParameter p1 = new EntityParameter("SubscriptionID", DbType.Int32)
{
Value = subscriptionID.HasValue ? (object)subscriptionID : DBNull.Value,
}
Run Code Online (Sandbox Code Playgroud)
PS:
那不叫"三元运营商".它是一个三元运算符,但它被称为"条件运算符".
Eri*_*ert 15
虽然其他答案是正确的,但从它们的真实和相关陈述的意义上讲,这里有一些语言设计的微妙点尚未表达.许多不同因素有助于条件运算符的当前设计.
首先,希望尽可能多的表达具有可以仅从表达式的内容确定的明确类型.由于几个原因,这是可取的.例如:它使构建IntelliSense引擎变得更加容易.您输入x.M(some-expression.
和智能感知需要能够分析一些表达,确定其类型,并产生下拉之前的IntelliSense知道什么方法XM指.IntelliSense无法知道xM所指的是肯定M是否在看到所有参数之前被重载,但是你还没有输入第一个参数.
其次,我们更喜欢类型信息"从内到外"流动,因为正好我刚刚提到的场景:重载决策.考虑以下:
void M(object x) {}
void M(int x) {}
void M(string x) {}
...
M(b ? 1 : "hello");
Run Code Online (Sandbox Code Playgroud)
这应该怎么办?它应该调用对象超载吗?它有时会调用字符串重载并有时调用int重载吗?如果你有另一个超负荷M(IComparable x)
怎么办?比如说你什么时候选择它?
当类型信息"双向流动"时,事情变得非常复杂.说"我正在将这个东西分配给类型对象的变量,因此编译器应该知道选择对象作为"不洗的类型是可以的; 通常情况下,我们不知道您分配的变量的类型,因为这是我们正在试图弄清楚的过程.重载决策正是从参数类型中计算出参数类型的过程,参数类型是您为其分配参数的变量.如果参数的类型取决于它们被分配的类型,那么我们的推理就具有循环性.
类型信息确实为lambda表达式"双向流动"; 实施这项工作有效地带走了我一年中最好的一部分.我写了很多篇文章,描述了设计和实现编译器时遇到的一些困难,这些编译器可以根据表达式可能被使用的上下文,在类型信息流入复杂表达式的情况下进行分析.第一部分在这里:
您可能会说"好吧,好吧,我明白为什么我分配给对象的事实无法被编译器安全使用,我明白为什么表达式必须具有明确的类型,但为什么不是类型表达式对象,因为int和string都可以转换为对象?" 这让我想到了第三点:
第三,C#的一个微妙但一贯应用的设计原则是"不要通过魔法生成类型".当给出一个表达式列表时,我们必须从中确定一个类型,我们确定的类型总是在列表中的某个位置.我们永远不会为一种新型装扮,并为您选择它; 你得到的类型总是你给我们选择的类型.如果你说要在一组类型中找到最佳类型,我们会找到这组类型中的最佳类型IN.在集合{int,string}中,没有最常见的类型,例如"Animal,Turtle,Mammal,Wallaby".此设计决策适用于条件运算符,类型推断统一场景,隐式类型数组类型的推断等.
这个设计决策的原因在于它使普通人更容易计算出编译器在必须确定最佳类型的任何给定情况下要做的事情; 如果你知道那种类型就在那里,盯着你看,那将会被选中,那么找出将要发生的事情要容易得多.
它还避免了在发生冲突时我们必须制定关于什么是一组类型的最佳常见类型的复杂规则.假设你有类型{Foo,Bar},其中两个类都实现了IBlah,并且这两个类都继承自Baz.哪个是最好的常见类型,IBlah,它们都实现了,或Baz,两者都延伸?我们不想回答这个问题; 我们想完全避免它.
最后,我注意到C#编译器实际上在某些模糊的情况下确定了类型错误的类型.我的第一篇文章就在这里:
http://blogs.msdn.com/ericlippert/archive/2006/05/24/type-inference-woes-part-one.aspx
事实上,编译器做得恰到好处并且规范是错误的,这是有争议的; 在我看来,实现设计比规范设计更好.
无论如何,这只是设计三元运算符的这个特定方面的几个原因.还有其他的玄机在这里,例如,CLR验证如何确定分支通道的一组给定是否保证离开堆栈中的正确类型所有可能的路径.详细讨论这将使我走得更远.