C#有多大用处?运营商?

cap*_*aig 24 c# syntactic-sugar

所以我一直对这个感兴趣?运营商,但仍然无法使用它.当我做的事情时,我通常会想到:

var x = (someObject as someType).someMember;
Run Code Online (Sandbox Code Playgroud)

如果someObject有效且someMember为null,我可以这样做

var x = (someObject as someType).someMember ?? defaultValue;
Run Code Online (Sandbox Code Playgroud)

但是当someObject为null时,我几乎总是遇到问题,而且?? 并没有帮助我使这个更清洁,而不是自己做空检查.

你们找到了什么用途?在实际情况?

Mar*_*lin 32

??操作是一样的聚结在SQL方法,它可以让你的第一个非空值.

var result = value1 ?? value2 ?? value3 ?? value4 ?? defaultValue;
Run Code Online (Sandbox Code Playgroud)

  • @jphofmann:我目前工作中的一个很好的用例.我必须通过调用函数来搜索复杂的业务对象.如果搜索失败,则搜索功能返回null.我必须反复搜索不同的搜索参数,直到找到一个对象.从这样的代码中很容易理解搜索规则:`var result = Find("A")?? 找("Y")?? 查找("Q");`使用`??`可以使您的代码更紧凑和可读. (2认同)

Jus*_*ant 27

我同意你的看法?运算符通常用途有限 - 如果某些内容为空,则提供后备值非常有用,但如果您希望继续向下钻取有时属性或方法,则无法防止出现空引用异常.空引用.

恕我直言,还需要什么?是一个"null-dereference"运算符,它允许您将长属性和/或方法链链接在一起,例如,a.b().c.d().e无需测试每个中间步骤的null-ness.在Groovy的语言有一个安全导航操作,这是非常方便的.

幸运的是,C#团队似乎意识到了这个功能差距.请参阅此connect.microsoft.com建议,以便C#团队向C#语言添加null-dereference运算符.

我们收到了很多类似于此功能的请求."?" 在社区讨论中提到的版本最接近我们的心 - 它允许你在每个"点"测试null,并与现有的很好地组合?运营商:

a?.b?.c ?? d

意味着如果a,ab或abc中的任何一个为null,则使用d代替.

我们正在考虑将来发布这个版本,但它不会出现在C#4.0中.

再次感谢,

Mads Torgersen,C#语言PM

如果您还想在C#中使用此功能,请将您的投票添加到连接站点上的建议中!:-)

我用来解决缺少此功能的一种解决方法是像本博文中所描述的扩展方法,允许这样的代码:

string s = h.MetaData
            .NullSafe(meta => meta.GetExtendedName())
            .NullSafe(s => s.Trim().ToLower())
Run Code Online (Sandbox Code Playgroud)

h.MetaData.GetExtendedName().Trim().ToLower()如果h,h.MetaData或h.MetaData.GetExtendedName()为null,则此代码返回或返回null.我还扩展了它以检查null或空字符串,或null或空集合.这是我用来定义这些扩展方法的代码:

public static class NullSafeExtensions
{
    /// <summary>
    /// Tests for null objects without re-computing values or assigning temporary variables.  Similar to 
    /// Groovy's "safe-dereference" operator .? which returns null if the object is null, and de-references
    /// if the object is not null.
    /// </summary>
    /// <typeparam name="TResult">resulting type of the expression</typeparam>
    /// <typeparam name="TCheck">type of object to check for null</typeparam>
    /// <param name="check">value to check for null</param>
    /// <param name="valueIfNotNull">delegate to compute if check is not null</param>
    /// <returns>null if check is null, the delegate's results otherwise</returns>
    public static TResult NullSafe<TCheck, TResult>(this TCheck check, Func<TCheck, TResult> valueIfNotNull)
        where TResult : class
        where TCheck : class
    {
        return check == null ? null : valueIfNotNull(check);
    }

    /// <summary>
    /// Tests for null/empty strings without re-computing values or assigning temporary variables
    /// </summary>
    /// <typeparam name="TResult">resulting type of the expression</typeparam>
    /// <param name="check">value to check for null</param>
    /// <param name="valueIfNotNullOrEmpty">delegate to compute non-null value</param>
    /// <returns>null if check is null, the delegate's results otherwise</returns>
    public static TResult CheckNullOrEmpty<TResult>(this string check, Func<string, TResult> valueIfNotNullOrEmpty)
        where TResult : class
    {
        return string.IsNullOrEmpty(check) ? null : valueIfNotNullOrEmpty(check);
    }
    /// <summary>
    /// Tests for null/empty collections without re-computing values or assigning temporary variables
    /// </summary>
    /// <typeparam name="TResult">resulting type of the expression</typeparam>
    /// <typeparam name="TCheck">type of collection or array to check</typeparam>
    /// <param name="check">value to check for null</param>
    /// <param name="valueIfNotNullOrEmpty">delegate to compute non-null value</param>
    /// <returns>null if check is null, the delegate's results otherwise</returns>
    public static TResult CheckNullOrEmpty<TCheck, TResult>(this TCheck check, Func<TCheck, TResult> valueIfNotNullOrEmpty)
        where TCheck : ICollection
        where TResult : class
    {
        return (check == null || check.Count == 0) ? null : valueIfNotNullOrEmpty(check);
    }
}
Run Code Online (Sandbox Code Playgroud)


Bra*_*don 22

我通常将它用于字符串或可空类型.

string s = someString ?? "Default message";
Run Code Online (Sandbox Code Playgroud)

比...更容易

   string s;
   if(someString == null)
     s = "Default Message";         
   else
     s = someString;
Run Code Online (Sandbox Code Playgroud)

要么

  string s = someString != null ? someString : "Default Message";
Run Code Online (Sandbox Code Playgroud)

  • 非常正确,但它不等同于你的中间语句,好像someString == string.Empty,?? 操作员不会开火. (2认同)

Gre*_*ech 11

我经常将它用于属性中的懒惰实例化对象,例如

public MyObject MyProperty
{
    get
    {
        return this.myField ?? (this.myField = new MyObject());
    }
}
Run Code Online (Sandbox Code Playgroud)

这利用了这样的事实:在C#中,赋值是一个表达式,因此您可以在同一语句中分配和使用表达式的结果(赋值).我仍然觉得这个代码模式略显肮脏,但它比替代方案(下面)更为简洁,所以它只是胜利.

public MyObject MyProperty
{
    get
    {
        if (this.myField == null)
        {
            this.myField = new MyObject();
        }

        return this.myField;
    }
}
Run Code Online (Sandbox Code Playgroud)


Jes*_*cer 8

正如FYI一样,三元运算符从空合并运算符生成不同的IL序列.第一个看起来像这样:

// string s = null;
// string y = s != null ? s : "Default";
    ldloc.0
    brtrue.s notnull1
    ldstr "Default"
    br.s isnull1
    notnull1: ldloc.0
    isnull1: stloc.1
Run Code Online (Sandbox Code Playgroud)

而后者看起来像这样:

// y = s ?? "Default";
    ldloc.0
    dup
    brtrue.s notnull2
    pop
    ldstr "Default"
    notnull2: stloc.1
Run Code Online (Sandbox Code Playgroud)

基于此,我会说空合并运算符是针对其目的进行优化的,而不仅仅是语法糖.


Cyl*_*Cat 7

?? 实际上是一个空检查操作符.

您的代码遇到麻烦的原因是,如果"someObject为null,则.someMember是null对象上的属性.您必须首先检查someObject是否为null.

编辑:

我应该补充一点是,我确实找到了?非常有用,特别是在处理数据库输入时,特别是从LINQ,但在其他情况下.我大量使用它.