空传播算子的性能与编译

Performance and compilation of null propagation operator

这里特指我要重写的一些C#属性

原始属性之一的示例:

public double? PartQuantity
{
    get
    {
        if( MaintenanceRequestPart != null )
            return MaintenanceRequestPart.ReportedQuantity.HasValue
                ? (double?)MaintenanceRequestPart.ReportedQuantity.Value
                : null;

        return null;
    }
}

这将更改为:

public double? PartQuantity => MaintenanceRequestPart?.ReportedQuantity;

注1: MaintenanceRequestPart可以为空

注 2: MaintenanceRequestPart.ReportedQuantity 是一个可为 null 的 double

这会节省还是增加一些 operations/branching/overhead?我很好奇什么?运算符一旦变成中间语言,实际上就在幕后进行翻译。

这很好。唯一的区别是它将在 IL 级别 上复制此变量的引用。所以这基本上意味着:

public double? PartQuantity => MaintenanceRequestPart?.ReportedQuantity;

等同于:

public double? PartQuantity 
{
    get
    {
        var value = MaintenanceRequestPart;
        return value == null ? null : value.ReportedQuantity;
    }
}

为什么要进行额外的复制?答案很简单——如果这个值是从不同的线程访问的,则为原子决策捕获值。这在处理事件时非常有用(因此它不会在“?”运算符中间抛出 NullReferenceException):

public event EventHandler OnSomethingHappened;
...
OnSomethingHappened?.Invoke(this, new EventArgs());

但是,不要害怕,它不会对性能产生合理的影响。

结论:你可以在不丢失任何东西的情况下进行重构