2012-02-13 2 views
26

아래 코드가있는 경우 Action을 호출해야합니까, 아니면 Action.Invoke를 호출해야합니까?Action.Invoke를 사용하는 것이 가장 좋습니다.

public class ClassA 
{ 
    public event Action<string> OnAdd; 

    private void SomethingHappened() 
    { 
    if (OnAdd != null) 
    OnAdd("It Happened"); //Should it be OnAdd.Invoke("It Happened") ??????? 
    } 
} 

public class ClassB 
{ 

    public ClassB() 
    { 
    var myClass = new ClassA(); 
    myClass.OnAdd += Add; 
    } 

    private void Add(string Input) 
    { 
    //do something 
    } 
} 
+3

C# 6에서는 새로운 OnAdd? .Invoke ("It Happened"); 구문을 사용하는 것이 더 일반적 일 수 있습니다. – Betty

+0

위의 주석에 조금 더 자세히 설명해주십시오. 이 예제는 Null 조건부 연산자 인 C# 6의 기능을 사용합니다. ? OnAdd가 null이므로 예외를 방지하면 연산자는 Invote 메서드 호출을 금지합니다. 이것에 의해, 이하의 해답에 명시적인 null 체크를 실시하지 않는 코드를 작성할 수 있습니다. 자세한 내용은 https://msdn.microsoft.com/en-us/magazine/dn802602.aspx를 참조하십시오. – Mark

+0

여기에 약간의 비교 : https://jacksondunstan.com/articles/3283. –

답변

32

둘은 동일합니다. 컴파일러는 OnAdd("It Happened");OnAdd.Invoke("It Happened");으로 변환합니다.

나는 그것이 선호의 문제라고 생각하지만 개인적으로 더 간결한 형식을 선호합니다.

일반적으로 OnAdd이 검사 될 때 null이 아니지만 해당 시간에 해당 경쟁 조건을 피하기 위해 호출하기 전에 클래스 수준 대리자의 로컬 복사본을 가져 오는 것이 좋습니다

private void SomethingHappened() 
{ 
    Action<string> local = OnAdd; 
    if (local != null) 
    { 
    local("It Happened"); 
    } 
} 
+0

경주의 예에서 차이점이 보이지 않는다면 미안합니다. – Jon

+0

@ 존 : 두 개의 스레드가 관련되어 있는지 생각해보십시오. 한 스레드가 다른 스레드가 null이 아니라 앞에 테스트 한 후에 * OnAdd를 설정합니다. 그것을 호출 ...당신의 코드에서'NullReferenceException'으로 끝날 것입니다. –

+0

@JonSkeet Gotcha! 이 연습은 이런 모든 호출 코드에서 권장됩니까? – Jon

10

두 구조는 완전히 동일합니다.

OnAdd("It Happened"); 

은 단지 구문 설탕입니다. 장면 뒤에서 컴파일러는 결과 MSIL에서 Action<T>.Invoke에 대한 호출을 내 보냅니다. 그래서 당신에게 더 읽기 쉬운 것을 사용하십시오 (나를 위해 OnAdd("It Happened");는 충분히 읽을 수 있습니다).

6

very strange bug around anonymous functions으로 실행하지 않는 한 정확하게 동일합니다.

개인적으로는 은 일반적으로입니다. 바로 가기 양식을 사용하지만 가끔씩은 더 읽기 쉽도록 Invoke을 명시 적으로 호출합니다. 예를 들어, 당신은 할 수 있습니다 여기에

if (callAsync) 
{ 
    var result = foo.BeginInvoke(...); 
    // ... 
} 
else 
{ 
    foo.Invoke(...); 
    // ... 
} 

Invoke의 명시 적 사용은 대칭 유용합니다.

Invoke 메서드를 호출하는 측면에서 명시 적으로 지정하지 않았지만 대리자 호출에 대한 자세한 내용은 C# 4 사양의 15.4 단원을 참조하십시오.

5

뭔가 내가 더를 사용하는 Invoke을 장려 수 있으므로 최신의 C# 6 출시와 함께이를 발견하고 누군가 도움이 나는 경우에이 오래된 질문에 추가 거라고 생각 :

"올드"방법 : (빈 이벤트 위임 패턴과 유사)

Action<string> doSomething = null; // or not null 
if (doSomething != null) 
    doSomething("test"); 

가능한 실용적인 방법 :

Action<string> doSomethingPragmatic = s => { }; // empty - might be overwritten later 
doSomethingPragmatic("test"); 

C# 6 :

Action<string> doSomethingCs6 = null; // or not null 
doSomethingCs6?.Invoke("test"); 

// Not valid C#: 
// doSomethingCs6?("test") 
// doSomethingCs6?.("test") 
+0

ReSharper는이 새로운 C# 6 스타일을 권장합니다. –

관련 문제