方法调用如果在C#中不为null

Jak*_*old 82 c# null

有可能以某种方式缩短这种说法吗?

if (obj != null)
    obj.SomeMethod();
Run Code Online (Sandbox Code Playgroud)

因为我碰巧写了很多东西而且很烦人.我唯一能想到的就是实现Null Object模式,但这并不是我每次都能做到的,而且它肯定不是缩短语法的解决方案.

和事件类似的问题,在哪里

public event Func<string> MyEvent;
Run Code Online (Sandbox Code Playgroud)

然后调用

if (MyEvent != null)
    MyEvent.Invoke();
Run Code Online (Sandbox Code Playgroud)

Mar*_*ell 138

从C#6开始,你可以使用:

MyEvent?.Invoke();
Run Code Online (Sandbox Code Playgroud)

要么:

obj?.SomeMethod();
Run Code Online (Sandbox Code Playgroud)

?.是null-传播算子,并且将导致.Invoke()到短路时的操作数是null.操作数只能访问一次,因此不存在"检查和调用之间的值更改"问题的风险.

===

在C#6之前,没有:没有零安全魔法,只有一个例外; 扩展方法 - 例如:

public static void SafeInvoke(this Action action) {
    if(action != null) action();
}
Run Code Online (Sandbox Code Playgroud)

现在这是有效的:

Action act = null;
act.SafeInvoke(); // does nothing
act = delegate {Console.WriteLine("hi");}
act.SafeInvoke(); // writes "hi"
Run Code Online (Sandbox Code Playgroud)

在事件的情况下,这具有删除竞争条件的优点,即您不需要临时变量.所以通常你需要:

var handler = SomeEvent;
if(handler != null) handler(this, EventArgs.Empty);
Run Code Online (Sandbox Code Playgroud)

但是:

public static void SafeInvoke(this EventHandler handler, object sender) {
    if(handler != null) handler(sender, EventArgs.Empty);
}
Run Code Online (Sandbox Code Playgroud)

我们可以简单地使用:

SomeEvent.SafeInvoke(this); // no race condition, no null risk
Run Code Online (Sandbox Code Playgroud)

  • 我对此有点矛盾。对于操作或事件处理程序(通常更独立)来说,这是有道理的。不过,我不会破坏常规方法的封装。这意味着在单独的静态类中创建方法,我认为失去封装和降低可读性/代码组织总体上不值得在本地可读性上进行微小的改进 (2认同)

Vim*_*mes 26

你要找的是Null Conditional(不是"合并")运算符:?..它从C#6开始提供.

你的例子就是obj?.SomeMethod();.如果obj为null,则没有任何反应.当方法有参数时,例如obj?.SomeMethod(new Foo(), GetBar());,如果obj为null,则不计算参数,这对于评估参数会产生副作用很重要.

链接是可能的: myObject?.Items?[0]?.DoSomething()


kat*_*yte 10

一种快速扩展方法:

    public static void IfNotNull<T>(this T obj, Action<T> action, Action actionIfNull = null) where T : class {
        if(obj != null) {
            action(obj);
        } else if ( actionIfNull != null ) {
            actionIfNull();
        }
    }
Run Code Online (Sandbox Code Playgroud)

例:

  string str = null;
  str.IfNotNull(s => Console.Write(s.Length));
  str.IfNotNull(s => Console.Write(s.Length), () => Console.Write("null"));
Run Code Online (Sandbox Code Playgroud)

或者:

    public static TR IfNotNull<T, TR>(this T obj, Func<T, TR> func, Func<TR> ifNull = null) where T : class {
        return obj != null ? func(obj) : (ifNull != null ? ifNull() : default(TR));
    }
Run Code Online (Sandbox Code Playgroud)

例:

    string str = null;
    Console.Write(str.IfNotNull(s => s.Length.ToString());
    Console.Write(str.IfNotNull(s => s.Length.ToString(), () =>  "null"));
Run Code Online (Sandbox Code Playgroud)


Sve*_*ler 5

事件可以使用一个永远不会被删除的空默认委托来初始化:

public event EventHandler MyEvent = delegate { };
Run Code Online (Sandbox Code Playgroud)

无需进行空值检查。

[更新,感谢 Bevan 指出这一点]

但请注意可能的性能影响。我所做的快速微基准测试表明,使用“默认委托”模式时,处理没有订阅者的事件会慢 2-3 倍。(在我的双核 2.5GHz 笔记本电脑上,这意味着 279 毫秒:筹集 5000 万个未订阅事件需要 785 毫秒。)。对于应用程序热点,这可能是一个需要考虑的问题。