在赋值左侧使用空条件运算符

Posted

技术标签:

【中文标题】在赋值左侧使用空条件运算符【英文标题】:Using the null-conditional operator on the left-hand side of an assignment 【发布时间】:2016-06-23 13:30:48 【问题描述】:

我有几页,每页都有一个名为Data 的属性。在另一个页面上,我将这些数据设置为:

if (MyPage1 != null)
    MyPage1.Data = this.data;
if (MyPage2 != null)
    MyPage2.Data = this.data;
if (MyPage3 != null)
    MyPage3.Data = this.data;

有没有可能在MyPage 上使用空条件运算符?我正在考虑这样的事情:

MyPage?.Data = this.data;

但是当我这样写时,我得到以下错误:

赋值的左侧必须是变量、属性或索引器。

我知道这是因为MyPage 可能为空,而左侧不再是变量。

并不是说我不能像我已经拥有它那样使用它,而是我只是想知道是否有可能对此使用空条件运算符。

【问题讨论】:

您应该能够创建一个SetData 方法并执行MyPage1?.SetData(this.data); Why C# 6.0 doesn't let to set properties of a non-null nullable struct when using Null propagation operator?的可能重复 空传播/条件运算符用于访问属性,而不是设置它们。因此你不能使用它。 我个人认为这是当前实现的一个错误。左侧的属性是调用属性设置器方法的简写,因此您应该可以使用 ?在 null 属性上,就好像您已显式调用 set 方法本身一样。 【参考方案1】:

空传播运算符返回一个值。而且由于在赋值的左侧必须有一个变量,而不是一个值,所以不能以这种方式使用它。

当然,您可以通过使用三元运算符来缩短内容,但另一方面,这并不能真正帮助提高可读性。

Joachim Isaksson 对您的问题的评论显示了一种应该可行的不同方法。

【讨论】:

【参考方案2】:

正如 Joachim Isaksson 在 cmets 中建议的那样,我现在有一个方法 SetData(Data data) 并像这样使用它:

MyPage1?.SetData(this.data);
MyPage2?.SetData(this.data);
MyPage3?.SetData(this.data);

【讨论】:

【参考方案3】:

我想出了以下扩展,

public static class ObjectExtensions

    public static void SetValue<TValue>(this object @object, string propertyName, TValue value)
    
        var property = @object.GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
        if (property?.CanWrite == true)
            property.SetValue(@object, value, null);
    

可以全局调用;这仅适用于公共财产。

myObject?.SetValue("MyProperty", new SomeObject());

以下改进版本适用于任何东西,

public static void SetValue<TObject>(this TObject @object, Action<TObject> assignment)

    assignment(@object);

也可以全局调用,

myObject?.SetValue(i => i.MyProperty = new SomeObject());

但扩展名有些误导,因为 Action 并不完全需要分配。

【讨论】:

【参考方案4】:

参加聚会有点晚了,但我带着类似的问题来到这篇文章。我借鉴了 SetValue 方法的思想,创建了一个通用的扩展方法,如下:

/// <summary>
/// Similar to save navigation operator, but for assignment. Useful for += and -= event handlers. 
/// If <paramref name="obj"/> is null, then <paramref name="action"/> is not performed and false is returned.
/// If <paramref name="obj"/> is not null, then <paramref name="action"/> is performed and true is returned.
/// </summary>
public static bool SafeAssign<T>(this T obj , Action<T> action ) where T : class 

  if (obj is null) return false;
  action.Invoke(obj);
  return true;

示例用法,用于附加和分离事件处理程序:

public void Attach() => _control.SafeAssign(c => c.MouseDown += Drag);

public void Detach() => _control.SafeAssign(c => c.MouseDown-= Drag);

希望有人觉得它有用:)

【讨论】:

【参考方案5】:

试试这个 将所有页面添加到 myPageList。

IEnumerable<MyPage> myPageList;

foreach(MyPage myPage in myPageList)

if (myPage != null)
    myPage.Data = this.data;

【讨论】:

【参考方案6】:

你可以使用扩展方法

 public static void NCC<T>(this T instance, System.Action<T> func)
        where T : class

        if (instance != null)
        
            func(instance);
        


MyPage1.NCC(_=>_.Data = this.data);

【讨论】:

【参考方案7】:

一个通用的 SetValue 扩展方法(但仅适用于 ref 属性)将是:

    public static void SetValue<T>(this T property, T value)
    
        property = value;
    

并且会像这样使用

ButtonOrNull?.Visibility.SetValue(Visibility.Hidden);

【讨论】:

你测试过这个吗?这绝对不会起作用...T property 必须是 ref 参数才能使更改生效,因为您唯一要做的就是在函数内设置属性的本地副本,而您不能拥有this ref 扩展方法,C# 也不允许 ref 访问属性(与 VB 不同,这实际上是一种耻辱)。 哦,你说得非常对 ? - 它只适用于 ref 参数(所以在我的情况下它总是......偶然) @MikeMarynowski:实际上你现在可以拥有ref this 扩展方法(但阻止将属性传递给 ref 参数的限制仍然存在) @BenVoigt 不适合不受约束的T。值类型只能有 this ref

以上是关于在赋值左侧使用空条件运算符的主要内容,如果未能解决你的问题,请参考以下文章

3.运算符

如何在 WPF 中使用空条件运算符? [复制]

在处置模式中使用空条件运算符时 CA2213 触发

为啥要使用三元运算符而不为“真”条件赋值 (x = x ?: 1)

有人可以解释为啥条件运算符和赋值运算符一起使用时表现奇怪吗?

Coffeescript 中的存在条件赋值运算符