为什么 C# 在表达式中使用可空值时需要括号?
Why does C# require parentheses when using nullables in an expression?
我是 C# 的新手,在探索语言特性时,我遇到了一些奇怪的事情:
struct Foo
{
public Foo Identity() { return this; }
public static void Bar(Foo? foo)
{
Foo foo1 = foo?.Identity().Value; // Does not compile
Foo foo2 = (foo?.Identity()).Value; // Compiles
}
}
谁能给我解释一下为什么需要括号?
Could anyone explain to me why the parenthesis are needed?
因为Identity()
returns有Foo
(不是Foo?
)所以没有Value
属性。如果 foo
为 null,则 null 将通过 Identity
调用传播。
当你用括号括起来时,表达式的结果是一个Nullable<Foo>
,确实有一个Value
属性.
另请注意,如果 foo
是 空值,那么您将在没有值的 Nullable<Foo>
上调用 Value
,并且将在 运行-time 得到一个异常 。一些静态分析器会识别出您可能有空引用异常等待发生并警告您。
如果你将它们扩展为它们的等价物而不进行空值传播,它会更清楚:
Foo foo1;
if(foo != null)
{
foo1 = foo.Identity().Value; // not possible - Foo has no Value property.
}
else
{
foo1 = null; // also not possible
}
Foo foo2;
Foo? temp;
if(foo != null)
{
temp = foo.Identity();
}
else
{
temp = null; // actually a Nullable<Foo> with no value
}
foo2 = temp.Value; // legal, but will throw an exception at run-time if foo is null
If Identity()
returns Foo
, why does Foo foo3 = foo?.Identity();
not compile ?
相当于:
Foo foo3
if(foo != null)
{
foo3 = foo.Identity();
}
else
{
foo3 = null; // not possible
}
我认为 c# 团队这样做是一个很好的决定。考虑以下情况:
如果结构是:
struct Foo
{
public int ID { set; get; }
public Foo Identity() { return this; }
public static void Bar(Foo? foo)
{
int? foo1 = foo?.Identity().ID; // compile
Foo foo2 = (foo?.Identity()).Value; // Compiles
}
}
如果您不需要括号来访问 Nullable 结果,您将无法访问 ID
属性。由于以下将无法编译:
int? foo2 = (foo?.Identity()).GetValueOrDefault()?.ID
当你写 foo?.Identity().
时,.
之后的内容是 Identity()
返回的 Foo
类型。但是在 (foo?.Identity()).
中 .
之后的是 Foo?
,这是整个语句 foo?.Identity().
的实际结果
我是 C# 的新手,在探索语言特性时,我遇到了一些奇怪的事情:
struct Foo
{
public Foo Identity() { return this; }
public static void Bar(Foo? foo)
{
Foo foo1 = foo?.Identity().Value; // Does not compile
Foo foo2 = (foo?.Identity()).Value; // Compiles
}
}
谁能给我解释一下为什么需要括号?
Could anyone explain to me why the parenthesis are needed?
因为Identity()
returns有Foo
(不是Foo?
)所以没有Value
属性。如果 foo
为 null,则 null 将通过 Identity
调用传播。
当你用括号括起来时,表达式的结果是一个Nullable<Foo>
,确实有一个Value
属性.
另请注意,如果 foo
是 空值,那么您将在没有值的 Nullable<Foo>
上调用 Value
,并且将在 运行-time 得到一个异常 。一些静态分析器会识别出您可能有空引用异常等待发生并警告您。
如果你将它们扩展为它们的等价物而不进行空值传播,它会更清楚:
Foo foo1;
if(foo != null)
{
foo1 = foo.Identity().Value; // not possible - Foo has no Value property.
}
else
{
foo1 = null; // also not possible
}
Foo foo2;
Foo? temp;
if(foo != null)
{
temp = foo.Identity();
}
else
{
temp = null; // actually a Nullable<Foo> with no value
}
foo2 = temp.Value; // legal, but will throw an exception at run-time if foo is null
If
Identity()
returnsFoo
, why doesFoo foo3 = foo?.Identity();
not compile ?
相当于:
Foo foo3
if(foo != null)
{
foo3 = foo.Identity();
}
else
{
foo3 = null; // not possible
}
我认为 c# 团队这样做是一个很好的决定。考虑以下情况:
如果结构是:
struct Foo
{
public int ID { set; get; }
public Foo Identity() { return this; }
public static void Bar(Foo? foo)
{
int? foo1 = foo?.Identity().ID; // compile
Foo foo2 = (foo?.Identity()).Value; // Compiles
}
}
如果您不需要括号来访问 Nullable 结果,您将无法访问 ID
属性。由于以下将无法编译:
int? foo2 = (foo?.Identity()).GetValueOrDefault()?.ID
当你写 foo?.Identity().
时,.
之后的内容是 Identity()
返回的 Foo
类型。但是在 (foo?.Identity()).
中 .
之后的是 Foo?
,这是整个语句 foo?.Identity().