为什么这段代码在 C# 中无效?

发布于 2024-07-07 10:26:48 字数 834 浏览 14 评论 0原文

以下代码将无法编译:

string foo = "bar";
Object o = foo == null ? DBNull.Value : foo;

我得到:错误 1 ​​条件表达式的类型无法确定,因为“System.DBNull”和“字符串”之间没有隐式转换

要解决此问题,我必须做一些事情像这样:

string foo = "bar";
Object o = foo == null ? DBNull.Value : (Object)foo;

这种强制转换似乎毫无意义,因为这当然是合法的:

string foo = "bar";
Object o = foo == null ? "gork" : foo;

在我看来,当三元分支具有不同类型时,编译器不会自动将值装箱到类型对象...但是当它们具有相同类型时自动装箱是自动的。

在我看来,第一个语句应该是合法的......

任何人都可以描述为什么编译器不允许这样做以及为什么 C# 的设计者选择这样做? 我相信这在 Java 中是合法的......虽然我还没有验证这一点。

谢谢。

编辑:我要求了解为什么 Java 和 C# 会以不同的方式处理此问题,C# 中幕后发生的情况会导致此问题无效。 我知道如何使用三元,并且不是在寻找“更好的方法”来编码示例。 我了解 C# 中三元的规则,但我想知道为什么...

编辑 (Jon Skeet):删除了“自动装箱”标签,因为这个问题不涉及装箱。

The following code will not compile:

string foo = "bar";
Object o = foo == null ? DBNull.Value : foo;

I get: Error 1 Type of conditional expression cannot be determined because there is no implicit conversion between 'System.DBNull' and 'string'

To fix this, I must do something like this:

string foo = "bar";
Object o = foo == null ? DBNull.Value : (Object)foo;

This cast seems pointless as this is certainly legal:

string foo = "bar";
Object o = foo == null ? "gork" : foo;

It seems to me that when the ternary branches are of different types, the compiler will not autobox the values to the type object...but when they are of the same type then the autoboxing is automatic.

In my mind the first statement should be legal...

Can anyone describe why the compiler does not allow this and why the designers of C# chose to do this? I believe this is legal in Java...Though I have not verified this.

Thanks.

EDIT: I am asking for an understanding of why Java and C# handle this differently, what is going on underneath the scenes in C# that make this invalid. I know how to use ternary, and am not looking for a "better way" to code the examples. I understand the rules of ternary in C#, but I want to know WHY...

EDIT (Jon Skeet): Removed "autoboxing" tag as no boxing is involved in this question.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

墨洒年华 2024-07-14 10:26:48

编译器要求第二个和第三个操作数的类型相同,或者一个可以隐式转换为另一个。 在您的情况下,类型是 DBNull 和 string,这两种类型都不能隐式转换为另一种。 将它们中的任何一个转换为对象可以解决这个问题。

编辑:看起来它在 Java 中确实是合法的。 当涉及到方法重载时,它是如何解决该做什么的,我不确定......我刚刚查看了 JLS,当有两个不兼容的引用时,非常不清楚条件的类型是什么涉及的类型。 C# 的工作方式有时可能会更令人恼火,但在我看来它更清晰。

C# 3.0 规范的相关部分是 7.13,条件运算符:

第二个和第三个操作数
?:操作员控制的类型
条件表达式。 设 X 和 Y 为
第二个和第三个的类型
操作数。 那么,

  • 如果 X 和 Y 是同一类型,则这就是条件的类型
  • 否则,如果存在从 X 到 Y 的隐式转换(第 6.1 节),
    但不是从 Y 到 X,那么 Y 就是
    条件表达式的类型。
  • 否则,如果存在从 Y 到 X 的隐式转换(第 6.1 节),
    但不是从 X 到 Y,那么 X 就是
    条件表达式的类型。
  • 否则,无法确定表达式类型,并且编译时
    发生错误。

The compiler requires that either the types of second and third operands are the same, or that one is implicitly convertible to the other. In your case, the types are DBNull and string, neither of which is implicitly convertible to the other. Casting either of them to object solves that.

EDIT: Looks like it is indeed legal in Java. Quite how it works out what to do when it comes to method overloading, I'm not sure... I've just looked at the JLS, and it's extremely unclear about what the type of the conditional is when there are two incompatible reference types involved. The C# way of working may be more irritating occasionally, but it's clearer IMO.

The relevant section of the C# 3.0 spec is 7.13, the 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
  • Otherwise, if an implicit conversion (§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 (§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.
相权↑美人 2024-07-14 10:26:48

DBNull.Value 返回类型 DBNull

您希望类型为字符串

虽然string可以是null,但它不能是DBNull

在代码中,等于右侧的语句在分配给对象之前执行。

基本上,如果您使用:

[condition] ? true value : false value;

在 .Net 中,在将 true 和 false 选项分配给任何内容之前,都需要隐式转换为相同类型。

这是 C# 处理类型安全方式的结果。 例如以下内容是有效的:

string item = "item";

var test = item != null ? item : "BLANK";

C#3 不支持动态类型,那么什么是测试? 在 C# 中,每个赋值也是一个带有返回值的语句,因此尽管 var 构造在 C#3 中是新的,但 equals 右侧的语句始终必须解析为单一类型。

在 C#4 及更高版本中,您可以显式支持动态类型,但我认为这没有帮助。

DBNull.Value returns type DBNull.

You want the type to be string.

While string can be null it cannot be a DBNull.

In your code the statement on the right of the equals executes before assignment to the object.

Basically if you use:

[condition] ? true value : false value;

In .Net both the true and false options need to be implicitly convertible to the same type, before whatever you assign them to.

This is a result of how C# deals with type-safety. For instance the following is valid:

string item = "item";

var test = item != null ? item : "BLANK";

C#3 doesn't support dynamic types, so what is test? In C# every assignment is also a statement with a return value, so although the var construct is new in C#3 the statement on the right of the equals always has to resolve to a single type.

In C#4 and above you can explicitly support dynamic types, but I don't think that helps here.

青朷 2024-07-14 10:26:48

顺便说一句,您的代码是一种特殊情况,根本不必使用条件运算符。 相反,空合并运算符更合适(但仍然需要强制转换):

object result = (object)foo ?? DBNull.Value;

By the way, your code is a special case that doesn't have to use the conditional operator at all. Instead, the null coalesce operator is more appropriate (but still requires casting):

object result = (object)foo ?? DBNull.Value;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文