programing tip

C #에서 null이 아닌 경우 메서드 호출

itbloger 2020. 9. 24. 07:37
반응형

C #에서 null이 아닌 경우 메서드 호출


어떻게 든이 진술을 단축 할 수 있습니까?

if (obj != null)
    obj.SomeMethod();

이 글을 많이 써서 꽤 짜증이 나기 때문입니다. 내가 생각할 수있는 유일한 방법은 Null Object 패턴 을 구현하는 것입니다 . 그러나 그것은 매번 할 수있는 일이 아니며 구문을 단축하는 해결책도 아닙니다.

그리고 이벤트와 유사한 문제는

public event Func<string> MyEvent;

그런 다음 호출

if (MyEvent != null)
    MyEvent.Invoke();

C # 6부터는 다음을 사용할 수 있습니다.

MyEvent?.Invoke();

또는:

obj?.SomeMethod();

?.널 전파 연산자이며,이 발생할 .Invoke()오퍼랜드 인 경우 단락 될 null. 피연산자는 한 번만 액세스되므로 "확인 및 호출 사이의 값 변경"문제의 위험이 없습니다.

===

C # 6 이전에는 아니요 : 한 가지 예외를 제외하고는 null-safe 마법이 없습니다. 확장 방법-예 :

public static void SafeInvoke(this Action action) {
    if(action != null) action();
}

이제 이것은 유효합니다 :

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

이벤트의 경우 경쟁 조건을 제거 할 수 있다는 장점이 있습니다. 즉, 임시 변수가 필요하지 않습니다. 따라서 일반적으로 다음이 필요합니다.

var handler = SomeEvent;
if(handler != null) handler(this, EventArgs.Empty);

하지만 함께:

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

간단하게 사용할 수 있습니다.

SomeEvent.SafeInvoke(this); // no race condition, no null risk

당신이 찾고있는 것은 Null Conditional ( "coalescing"아님) 연산자 : ?.. C # 6부터 사용할 수 있습니다.

귀하의 예는 obj?.SomeMethod();. obj가 null이면 아무 일도 일어나지 않습니다. 메소드에 인수가있는 경우, 예를 들어 obj?.SomeMethod(new Foo(), GetBar());인수 obj가 null이면 평가되지 않습니다 . 인수 평가에 부작용이 있는지 여부가 중요합니다.

그리고 연결이 가능합니다. myObject?.Items?[0]?.DoSomething()


빠른 확장 방법 :

    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();
        }
    }

예:

  string str = null;
  str.IfNotNull(s => Console.Write(s.Length));
  str.IfNotNull(s => Console.Write(s.Length), () => Console.Write("null"));

또는 대안으로 :

    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));
    }

예:

    string str = null;
    Console.Write(str.IfNotNull(s => s.Length.ToString());
    Console.Write(str.IfNotNull(s => s.Length.ToString(), () =>  "null"));

이벤트는 제거되지 않는 빈 기본 델리게이트로 초기화 할 수 있습니다.

public event EventHandler MyEvent = delegate { };

널 검사가 필요하지 않습니다.

[Update, thanks to Bevan for pointing this out]

Be aware of the possible performance impact, though. A quick micro benchmark I did indicates that handling an event with no subscribers is 2-3 times slower when using the the "default delegate" pattern. (On my dual core 2.5GHz laptop that means 279ms : 785ms for raising 50 million not-subscribed events.). For application hot spots, that might be an issue to consider.


Yes, in C# 6.0 -- https://msdn.microsoft.com/en-us/magazine/dn802602.aspx.

object?.SomeMethod()

This article by Ian Griffiths gives two different solutions to the problem that he concludes are neat tricks that you should not use.


Cerating extention method like one suggested does not really solve issues with race conditions, but rather hide them.

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

As stated this code is the elegant equivalent to solution with temporary variable, but...

The problem with both that it's possible that subsciber of the event could be called AFTER it has unsubscribed from the event. This is possible because unsubscription can happen after delegate instance is copied to the temp variable (or passed as parameter in the method above), but before delegate is invoked.

In general the behaviour of the client code is unpredictable in such case: component state could not allow to handle event notification already. It's possible to write client code in the way to handle it, but it would put unnecesssary responsibility to the client.

The only known way to ensure thread safity is to use lock statement for the sender of the event. This ensures that all subscriptions\unsubscriptions\invocation are serialized.

To be more accurate lock should be applied to the same sync object used in add\remove event accessor methods which is be default 'this'.


I agree with the answer by Kenny Eliasson. Go with Extension methods. Here is a brief overview of extension methods and your required IfNotNull method.

Extension Methods ( IfNotNull method )


Maybe not better but in my opinion more readable is to create an extension method

public static bool IsNull(this object obj) {
 return obj == null;
}

There is a little-known null operator in C# for this, ??. May be helpful:

http://weblogs.asp.net/scottgu/archive/2007/09/20/the-new-c-null-coalescing-operator-and-using-it-with-linq.aspx

참고URL : https://stackoverflow.com/questions/872323/method-call-if-not-null-in-c-sharp

반응형