如果变量为 null,则不执行任何操作的赋值操作
本文关键字:操作 任何 执行 赋值 变量 null 如果 | 更新日期: 2023-09-27 18:33:04
如果变量已经null
,我想有条件地为变量赋值。此外,如果该变量尚未null
则我希望什么都不发生,并且我希望能够使用单个运算符完成所有操作。
object a = null;
object b = new Something();
// this is essentially what I want but done with an operator:
if(a == null)
{
a = b;
}
// this is all I feel I have to work with,
a = a || b;
a = a ?? b;
a = a == null ? b : a;
// the above methods all end up performing a = a if a is not null
已更新
从 C# 8 开始,这可以通过 Null 合并赋值运算符来实现
a ??= b;
这只会在a
a
null
时将b
分配给
原始答案
虽然语法很啰嗦
(a is null?()=>a=b:(Action)(()=>{}))();
让我们把它分开
( // Expression starts here
a is null // If a == null...
? () => a = b // return lambda that assigns a = b
: (Action) ( // Else return next lambda casted as Action
() => {} // Empty lambda that does nothing
) // End cast
) // Expression ends here
(); // Execute it!
无论如何,如果if(a is null) { a = b; }
,我只会使用一个衬里
如果您担心在单个语句中完成所有这些操作,那么您就不走运了 - C# 在语言级别没有此功能,并且不支持运算符声明(如 F#(或赋值运算符的重载(如 C++(。但是,有几个选项,如果没有像您要求的那样优雅。
正如你提到的,if
语句,尽管它可以写成一行
if(a == null) a = b;
使用 ref
参数的帮助程序方法
public void AssignIfNull<T>(ref T target, T value)
{
if(target == null) target = value;
}
// ...
AssignIfNull(ref a, b);
请注意,上述内容不适用于属性,因为它们不能作为ref
参数传递。
编辑:虽然上述类似于Interlocked.CompareExchange
,但这样的替代返回第一个参数的原始值,因此它可能比实现上述方法更麻烦。
或者你可以小心地重写你的初始语句,在初始赋值中使用空合并(??
(运算符。
正如你所说,你需要一个if
语句。没有条件运算符在null
时不分配。在这种情况下,if
最合适(并非所有内容都必须是单行(。
最佳选择:
if(a == null)
{
a = b;
}
或:
a = a ?? b;
事实上,我认为后者作为一个简单的if
语句进行了优化。
将a
分配给自己也不错。使用对象引用,它只是内存地址的分配。对于值类型,这只是一小块数据。
如果a
实际上是属性资源库,请检查资源库内部的值是否有更改:
private string a;
public string A
{
get
{
return a;
}
set
{
if (value != a)
{
a = value;
}
}
}
我自己遇到这种情况后,我决定检查我处理这个问题的代码。我倾向于有两种解决方案,都涉及空合并运算符。
情况 1:初始化。使用上面的值,这将变为:
object a = null ?? something;
显然,我不会写那行代码(如果没有别的,resharper 会抱怨(。但这是正在发生的事情的本质。如果我在创建a
时有两个(或更多(值可用,那么我这样写。
情况 2:切勿设置 a
,但在使用a
时使用??
。在这种情况下,代码将是:
MethodTakingA(a ?? b);
如果有多个方法调用或其他我需要使用 ??
的地方,那么这是一个坏主意。
还有第三种情况,我做了你避免的确切任务。也就是说,当我的方法的一个参数可能为 null 时,我有一个默认值在这种情况下使用(而不是抛出ArgumentNullException
(。下面是一个示例:
public void Foo(string str)
{
str = str ?? String.Empty;
//Use str as needed below without fear that it might be null.
}
对于这种情况,我想要一个更好的答案,但我肯定不是在编写值得微优化该分配的代码,而理论答案是
string localStr = str ?? String.Empty;
只是添加一个新变量来添加一个。否则它对我没有用,所以我保持我的自我分配并忍受它。
我认为 C# 8.0 附带的新功能使这变得非常简单。有一个新的??= 检查变量的运算符,如果它为 null,则设置值,如果不是,则不算。
if (variable is null)
{
variable = expression;
}
只是在做
variable ??= expression;
在您的情况下,它是:
a ??= b;
作为一个语句,
var result = ((a == null) ? (a = b) : null);
然后可以丢弃result
的值。将a
和b
作为对象属性,并在a
的设置上添加Console.WriteLine()
将显示仅在以前为 null 时将其分配给
唯一阻止它完全干净的是创建了一个一次性变量result
;希望它仍然足够干净。
附录 - 我刚刚意识到你也可以使用:
var result = a ?? (a = b);
作为上述内容的更短版本。同样,仅当a
null
时,才会评估a = b
。