赋值操作如果变量为null则不执行任何操作?

时间:2014-12-04 15:21:34

标签: c# c#-4.0 variable-assignment

如果该变量已经是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

6 个答案:

答案 0 :(得分:7)

如果你担心在一个声明中完成这一切,那你就不走运了 - 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,但这样的替代方法会返回第一个参数的原始值,因此它可能更多地证明了比实施上述方法还要好。

或者你可以仔细地重写你的初始语句,以便在初始赋值中使用null-coalescing(??)运算符。

答案 1 :(得分:3)

正如您所说,if声明是您所需要的。在null时没有指定的条件运算符。在这种情况下if最合适(并非一切都必须是oneliner)。

最佳选择:

if(a == null)
{
    a = b;
}

或者:

a = a ?? b;

事实上,我认为后者被优化为简单的if语句。

a分配给自己也不错。使用对象引用,它只是内存地址的赋值。对于值类型,这只是一小部分数据。

如果a实际上是属性设置器,请在setter内部检查值是否有变化:

private string a;

public string A
{
    get
    {
        return a;
    }
    set
    {
        if (value != a)
        {
            a = value;
        }
    }
}

答案 2 :(得分:3)

虽然语法是详细的

(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; }

,我只会使用一个班轮

答案 3 :(得分:2)

我自己遇到这种情况,我决定检查我的代码处理这个问题。我倾向于有两个解决方案,都涉及空合并运算符。

案例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;

只是添加一个新变量来添加一个。否则我没有任何目的,所以我保留自己的任务并与之共存。

答案 4 :(得分:1)

作为单一陈述,

var result = ((a == null) ? (a = b) : null);

然后可以丢弃result的值。将ab作为对象属性,并在Console.WriteLine()的设置上添加a将显示它仅在以前为空时指定。

唯一阻止它完全清洁的是创建了一次性变量result;希望它还够干净。


附录 - 我刚刚意识到你也可以使用:

var result = a ?? (a = b);

作为上述更短的版本。同样,a = b仅在anull时进行评估。

答案 5 :(得分:0)

我认为C#8.0附带的新功能使此操作变得非常容易。有一个新的??= operators会检查变量,如果变量为null,则设置值,否则为空。

if (variable is null)
{
   variable = expression;
}

只是像

variable ??= expression;

您的情况是:

a ??= b;