代码之家  ›  专栏  ›  技术社区  ›  captncraig

C’s有多有用?操作员?

  •  24
  • captncraig  · 技术社区  · 16 年前

    所以我很好奇??操作员,但仍然无法使用。我通常在做如下事情时会想到:

    var x = (someObject as someType).someMember;
    

    如果someobject有效,somemember为空,我可以这样做

    var x = (someObject as someType).someMember ?? defaultValue;
    

    但几乎总是在某个对象为空时遇到问题,并且??这和我自己做空检查没什么区别。

    你们发现了什么用途??在实际情况下?

    13 回复  |  直到 8 年前
        1
  •  27
  •   Justin Grant    12 年前

    我同意你的观点??运算符的使用通常是有限的——如果某个值为空,则提供一个回退值很有用,但在希望继续深入到有时为空引用的属性或方法中时,防止空引用异常并不有用。

    嗯,还有什么比这更重要的??是一个“空解引用”运算符,允许您将长属性和/或方法链链接在一起,例如 a.b().c.d().e 无需测试每个中间步骤是否为空。这个 Groovy 语言有 Safe Navigation operator 而且非常方便。

    幸运的是,似乎C团队意识到了这一特性差异。看到这个 connect.microsoft.com suggestion 对于C团队,向C语言添加一个空的取消引用操作符。

    我们收到了很多关于 特点与此相似。“?”." 社区提到的版本 讨论最接近我们的心- 它允许您在处测试空值 每一个“点”,都与 现有的?操作员:

    A?B?C?D

    意思是如果A、A.B或A.B.C中的任何一个是 空,请改用d。

    我们正在考虑这一点 释放,但不会在C 4.0中。

    再次感谢

    Mads Torgersen,C语言PM

    如果您还希望在C中使用此功能,请将您的投票添加到 suggestion 在连接站点上!-)

    我用来解决这个特性的一个解决方法是扩展方法,如中所描述的 this blog post ,允许这样的代码:

    string s = h.MetaData
                .NullSafe(meta => meta.GetExtendedName())
                .NullSafe(s => s.Trim().ToLower())
    

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

    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);
        }
    }
    
        2
  •  32
  •   dance2die    8 年前

    这个 ?? 接线员就像 coalesce 方法,它将获取第一个非空值。

    var result = value1 ?? value2 ?? value3 ?? value4 ?? defaultValue;
    
        3
  •  22
  •   Ed Swangren    16 年前

    我通常将它用于字符串或可以为空的类型。

    string s = someString ?? "Default message";
    

    比容易

       string s;
       if(someString == null)
         s = "Default Message";         
       else
         s = someString;
    

      string s = someString != null ? someString : "Default Message";
    
        4
  •  11
  •   Greg Beech    16 年前

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

    public MyObject MyProperty
    {
        get
        {
            return this.myField ?? (this.myField = new MyObject());
        }
    }
    

    这充分利用了这样一个事实:在C中,赋值是一个表达式,因此您可以在同一语句中分配和使用表达式的结果(赋值)。我仍然觉得这个代码模式有点脏,但是它比其他的(下面)更简洁,所以它只是关于胜利。

    public MyObject MyProperty
    {
        get
        {
            if (this.myField == null)
            {
                this.myField = new MyObject();
            }
    
            return this.myField;
        }
    }
    
        5
  •  8
  •   Jesse C. Slicer    16 年前

    与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
    

    后者看起来是这样的:

    // y = s ?? "Default";
        ldloc.0
        dup
        brtrue.s notnull2
        pop
        ldstr "Default"
        notnull2: stloc.1
    

    基于此,我认为空合并操作符是为其目的而优化的,而不仅仅是语法上的糖分。

        6
  •  7
  •   Cylon Cat    16 年前

    是吗??是有效的空检查运算符。

    您的代码遇到问题的原因是,如果“someobject为空,那么.somemember是空对象上的属性”。您必须先检查某个对象是否为空。

    编辑:

    我应该补充一下,是的,我确实找到了??非常有用,特别是在处理数据库输入时,特别是从LINQ输入,但在其他情况下也同样有用。我用得很重。

        7
  •  3
  •   kenny    16 年前

    我一直把它和app.config一起使用

    string somethingsweet = ConfigurationManager.AppSettings["somesetting"] ?? "sugar";
    
        8
  •  2
  •   TheSean    16 年前

    最有用的是处理可为空的类型。

    bool? whatabool;
    //...
    bool realBool = whatabool ?? false;
    

    没有??你需要写下以下内容,这更让人困惑。

    bool realbool = false;
    if (whatabool.HasValue)
        realbool = whatabool.Value;
    

    我发现这个操作符对于可以为空的类型非常有用,但除此之外,我发现自己并没有经常使用它。绝对是一条很酷的捷径。

        9
  •  1
  •   plinth    16 年前

    我使用它来处理在正常操作下可以返回空值的方法。

    例如,假设我有一个容器类,它有一个get方法,如果容器不包含键(或者空是有效的关联),则该方法返回空值。然后我可能会这样做:

    string GetStringRep(object key) {
        object o = container.Get(key) ?? "null";
        return o.ToString();
    }
    

    显然,这两个序列是等效的:

    foo = bar != null ? bar : baz;
    foo = bar ?? baz;
    

    第二个只是更简洁。

        10
  •  1
  •   Jason Williams    16 年前

    用更紧凑的形式替换冗长的语法通常是个不错的主意。但通常情况下,它只是混淆了代码,而没有真正获得任何信息。现代标准提倡使用更长、更具描述性的变量名,并使用更详细的布局样式,以使代码更具可读性和可维护性。

    如果我要训练我的大脑快速分析??,我需要找到一种情况,在这种情况下,它显示出一种明显的优势——某种不能用另一种方式完成的事情,或者某种可以节省大量输入的地方。

    这是哪里??为我跌倒。它是有用的,所以很少,而且?:如果/否则是如此快速和易读的替代方案,那么使用不同的语法并没有什么新的意义。

    A=B??C??D?听起来不错。但我从来没必要这么做!

    我觉得恼人的是我想用它?但每次我想“哦,也许我能用?”“这里”,我意识到我不想使用对象本身,而是它的一个成员。

    name=(user==null)?“doe“:user.surname;

    不幸的是,??对这里没有帮助。

        11
  •  1
  •   Don Kirkby    16 年前

    在您的案例中,您可以将DefaultObject创建为静态属性,并使用如下所示…

    var x = (someObject as someType ?? someType.DefaultObject).someMember;
    

    其中,DefaultObject将返回静态只读对象。

    像eventargs.empty、string.empty等…

        12
  •  0
  •   Pickle    16 年前

    我和你有同样的问题,但是在使用linqtoxml的空间中,标记可能不在文档中,所以使用 ?? 在那个标签上对财产进行涂炭是不可行的。

    既然C中没有全局变量这类东西,所有的东西都在一个类中,所以我发现,像你一样??基本上是无用的。

    即使是一个简单的属性getter,比如:

    MyObject MyObj() { get { return _myObj ?? new MyObj(); } }
    

    可能最好是用初始值设定项…

    我认为和SQL中的情况一样,它在LINQ查询中会有一定的用处,但目前我还不能真正派生出一个。

        13
  •  0
  •   Joel Mueller    16 年前

    我经常在将字符串解析为其他数据类型时使用空合并运算符。我有一组扩展方法,它们包装了int32.typarse之类的东西,并返回一个可以为空的int,而不是将输出参数公开给我的其余代码。然后我可以在一行代码中解析一个字符串并在解析失败时提供一个默认值。

    // ToNullableInt(), is an extension method on string that returns null
    // if the input is null and returns null if Int32.TryParse fails.
    
    int startPage = Request.QueryString["start"].ToNullableInt() ?? 0;