호출 호출의 익명 메소드


131

Control.Invoke 내에서 익명으로 대리자를 호출하려는 구문에 약간의 문제가 있습니다.

우리는 여러 가지 다른 접근법을 시도했지만 모두 쓸모가 없었습니다.

예를 들면 다음과 같습니다.

myControl.Invoke(delegate() { MyMethod(this, new MyEventArgs(someParameter)); }); 

여기서 someParameter는이 메소드에 대해 로컬입니다.

위의 결과로 컴파일러 오류가 발생합니다.

대리자 형식이 아니므로 익명 메서드를 'System.Delegate'형식으로 변환 할 수 없습니다.

답변:


221

형식화 된 대리자가 아닌 Invoke/ BeginInvoke수락 하기 때문에 Delegate컴파일러에게 만들 대리자 형식을 알려야합니다. MethodInvoker(2.0) 또는 Action(3.5)는 일반적인 선택입니다 (서명은 동일 함). 이렇게 :

control.Invoke((MethodInvoker) delegate {this.Text = "Hi";});

매개 변수를 전달해야하는 경우 "캡처 된 변수"는 다음과 같습니다.

string message = "Hi";
control.Invoke((MethodInvoker) delegate {this.Text = message;});

(캐비티 : 캡처를 비동기로 사용하는 경우 약간 조심해야 하지만 동기화 는 양호합니다. 즉 위의 내용은 괜찮습니다)

또 다른 옵션은 확장 메소드를 작성하는 것입니다.

public static void Invoke(this Control control, Action action)
{
    control.Invoke((Delegate)action);
}

그때:

this.Invoke(delegate { this.Text = "hi"; });
// or since we are using C# 3.0
this.Invoke(() => { this.Text = "hi"; });

물론 다음과 같이 할 수 있습니다 BeginInvoke.

public static void BeginInvoke(this Control control, Action action)
{
    control.BeginInvoke((Delegate)action);
}

C # 3.0을 사용할 수 없으면 Form기본 클래스 에서 일반 인스턴스 메소드로 동일하게 수행 할 수 있습니다.


이 답변에서 첫 번째 솔루션에 매개 변수를 전달하려면 어떻게해야합니까? 나는이 해결책을 의미했다 : control.Invoke ((MethodInvoker) delegate {this.Text = "Hi";});
uzay95

1
Explicit 캐스트를 수행하지 않고 확장 메소드가 호출되는 이유는 무엇입니까?
P.Brian.Mackey

컴파일러는 사용법에서이를 유추 할 수 있기 때문입니다.
RoboJ1M

1
예전 Form.Load += Loader()대신 할 수있는 것과 같습니다Form.Load += new EventHandler(Loader())
RoboJ1M

49

실제로 위임 키워드를 사용할 필요는 없습니다. 람다를 매개 변수로 전달하십시오.

control.Invoke((MethodInvoker)(() => {this.Text = "Hi"; }));


13

대리인 유형을 만들어야합니다. 익명 메소드 작성에서 키워드 '대리인'은 약간 오해의 소지가 있습니다. 익명 대리자가 아닌 익명 메서드를 만들고 있습니다. 생성 한 메소드는 델리게이트에서 사용할 수 있습니다. 이처럼 :

myControl.Invoke(new MethodInvoker(delegate() { (MyMethod(this, new MyEventArgs(someParameter)); }));

8

완성도를 높이기 위해 Action 메소드 / 익명 메소드 조합을 통해 수행 할 수도 있습니다.

//Process is a method, invoked as a method group
Dispatcher.Current.BeginInvoke((Action) Process);
//or use an anonymous method
Dispatcher.Current.BeginInvoke((Action)delegate => {
  SomeFunc();
  SomeOtherFunc();
});

Invoke((Action) Process);최고의 답변입니다, 감사합니다!
Jinjinov

5

때로는 내 메소드에서 값을 반환하려고하기 때문에 다른 제안에 문제가 있습니다. 반환 값으로 MethodInvoker를 사용하려고하면 마음에 들지 않는 것 같습니다. 그래서 내가 사용하는 솔루션은 다음과 같습니다 (이 간결하게 만드는 방법을 듣고 매우 기쁩니다-c # .net 2.0을 사용하고 있습니다).

    // Create delegates for the different return types needed.
    private delegate void VoidDelegate();
    private delegate Boolean ReturnBooleanDelegate();
    private delegate Hashtable ReturnHashtableDelegate();

    // Now use the delegates and the delegate() keyword to create 
    // an anonymous method as required

    // Here a case where there's no value returned:
    public void SetTitle(string title)
    {
        myWindow.Invoke(new VoidDelegate(delegate()
        {
            myWindow.Text = title;
        }));
    }

    // Here's an example of a value being returned
    public Hashtable CurrentlyLoadedDocs()
    {
        return (Hashtable)myWindow.Invoke(new ReturnHashtableDelegate(delegate()
        {
            return myWindow.CurrentlyLoadedDocs;
        }));
    }

1

MethodInvoker 대신 Action을 사용하고 싶습니다. 더 짧고 깨끗해 보입니다.

Invoke((Action)(() => {
    DoSomething();
}));

// OR

Invoke((Action)delegate {
    DoSomething();
});

예 :

// Thread-safe update on a form control
public void DisplayResult(string text){
    if (txtResult.InvokeRequired){
        txtResult.Invoke((Action)delegate {
            DisplayResult(text);
        });
        return;
    }

    txtResult.Text += text + "\r\n";
}

0

이것이 왜 컴파일러에 차이가 있는지 이해하지 못했지만 이것으로 충분합니다.

public static class ControlExtensions
{
    public static void Invoke(this Control control, Action action)
    {
        control.Invoke(action);
    }
}

보너스 : Control.Invoke백그라운드 스레드에서 사용 하는 경우 컨트롤의 텍스트 / 진행률 / 활성화 상태를 업데이트하고 컨트롤이 이미 폐기되었는지는 신경 쓰지 않을 가능성이 있기 때문에 오류 처리를 추가 하십시오.

public static class ControlExtensions
{
    public static void Invoke(this Control control, Action action)
    {
        try
        {
            if (!control.IsDisposed) control.Invoke(action);
        }
        catch (ObjectDisposedException) { }
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.