2013-11-23 10 views
0

내 질문은 이러한 질문에 조금 비슷합니다 대의원을 사용하여 호출지연 방법은

replay a list of functions and parameters

C# delegate for two methods with different parameters

내 목표는 그들을 호출, 함수는 목록에서 해당 매개 변수 통화를 저장하는 것입니다 내 매니저 클래스에 의해 스케쥴 된 다른 스레드.

함수가 호출
  • , 매개 변수를 기억 함수 목록에 자신을 추가하고 함수가 종료되면
  • , 나는
  • 허용 (어떤이있는 경우) 반환 객체를 다시 얻으려면 값 나중에 호출 할 함수 목록
  • 완전히 다른 서명이있는 (그 중 일부는 반환 값 (bool, int, object ..)을 가지고 있고 일부는 반환하지 않았으며 메소드 파라미터의 수는 고정되어 있지 않다)
,

예컨대 I 그런 funstions 호출 할 :

ServerManager.addDoSomething(ServerManager.SERVICES.Login, serverURL, userName, password); // Login() with bool return type and 3 string parameters 
ServerManager.addDoSomething(ServerManager.SERVICES.Query, searchExpr);   // Query() with MyData return type and 1 string parameters 
ServerManager.addDoSomething(ServerManager.SERVICES.Modify, searchExpr, newVal);  // Modify() with int return type and 2 string parameters 
ServerManager.addDoSomething(ServerManager.SERVICES.Logout);     // Logout() with void return type and 0 parameters 

또는 그런

:

ServerManager.addDoSomething (() => ServerManager.SERVICES.Query (searchExpr));
ServerManager.addDoSomething (() => ServerManager.SERVICES.Modify (searchExpr, newVal)); ServerManager.addDoSomething (() => ServerManager.SERVICES.Logout()); ServerManager.addDoSomething (() => ServerManager.SERVICES.Login (serverURL, userName, password));

또는 인터페이스를 지원하는 다른 방법

..

어떻게해야 내 ServerManager.addDoSomething 방법 (또는 방법 다른 서명 경우)처럼, 어떤 데이터 구조를 사용해야합니까 (WHAT_SHOULD_I_STORE), I 경우 지연된 함수 호출을 지원하고 싶습니다. 반환 값은 어떻게 되 찾을 수 있습니까?

public class ServerManager 
{ 
    static List<WHAT_SHOULD_I_STORE> requestFIFO = new List<WHAT_SHOULD_I_STORE>(); 
    public static IServerConnection SERVICES ; 

    static BackgroundWorker worker = new BackgroundWorker(); 


    public ServerManager() 
    { 
     SERVICES = new ServerConnection(); 

     worker.DoWork += (o, ea) => 
     { 
      try 
      { 
       WHAT_SHOULD_I_STORE mr = null; 
       Application.Current.Dispatcher.Invoke(new Action(() => mr = popQueueElement())); 

      if (mr != null) 
       processRequestFromQueue(mr); 
      } 
      catch (Exception) 
      { 
      } 
     }; 

     worker.RunWorkerCompleted += (o, ea) => 
     { 
      worker.RunWorkerAsync(); 
     }; 

     if (! worker.IsBusy) worker.RunWorkerAsync(); 
    } 

    private WHAT_SHOULD_I_STORE popQueueElement() 
    { 
     if (requestFIFO != null && requestFIFO.Count > 0) 
     { 
      WHAT_SHOULD_I_STORE result = requestFIFO.ElementAt(0); 
      requestFIFO.Remove(result); 
      return result; 
     } 
     else 
      return null; 
    } 

    private addDoSomething(...) 
    { 
    //.... 
    } 

} 

public class ServerConnection : IServerConnection 
{ 
    // Concrete implementations of the IServerManager interface 
} 

public interface IServerConnection 
{ 
    bool Login (string serverURL, string userName, string password); 
    MyData Query (string serverURL, searchExpr); 
    int  Modify (string searchExpr, string newVal); 
    void Logout (); 
// ... 
} 
+0

업데이트 : 죄송 합니다만 "worker"라는 변수가 BackgroundWorker 클래스의 인스턴스라는 것을 놓쳤습니다. – user1802693

답변

0

I :

나는

public static void addDoSomething(Delegate delegateParameter, string ...); 
or 
public static void addDoSomething(Func<...> methodToCall, string ...); 
or 
public static void addDoSomething(Action methodToCall, string ...); 
or 
public static void addDoSomething(delegate methodToCall, string ...); 

내 수업 ... 내가 서명이 다른 방법에 대한 storeing을 위해 사용할 수 있다는, 그런 식으로 일반적인 위임을 할 수없는 생각 이 패턴을 사용합니다 :

ServerManager.addDoSomething(() => ServerManager.SERVICES.Logout()); 
ServerManager.addDoSomething(() => ServerManager.SERVICES.Modify (searchExpr, newVal)); 

그냥 일반 액션을 저장하십시오. 제공된 매개 변수가 클로저에 의해 캡처되므로 별도로 저장하는 것에 대해 걱정할 필요가 없으므로이 패턴을 모두 사용할 수 있습니다.

class Program 
{ 
    private static List<Action> actionList = new List<Action>(); 

    public static void Main(string[] args) 
    { 
     actionList.Add(() => Console.WriteLine("Test 1!")); 
     actionList.Add(() => Console.WriteLine("Test {0}!", 2)); 

     foreach (var action in actionList) 
     { 
      action(); 
     } 
    } 
} 

주의해야 할 점은 당신은 당신이 당신이 그것을 추가 한 후 메소드 인수로 전달하는 객체를 변경하는 경우주의 할 필요가있다,하지만 당신 전에 :

아래의 간단한 예제

무슨 뜻인지 보여줍니다 목록에서 귀하의 행동을 불러내십시오. 그렇게하면 액션에 사용 된 값도 수정됩니다 (클로저가 참조를 가져옵니다). 예를 들어

:

'2 시험'두 번 작업이 실행되기 전에 TestString에이 변경되기 때문에 출력 아래 코드 :

class Program 
{ 
    private static List<Action> actionList = new List<Action>(); 

    public static void Main(string[] args) 
    { 
     var testString = "Test 1"; 
     actionList.Add(() => Console.WriteLine(testString)); 

     testString = "Test 2"; 
     actionList.Add(() => Console.WriteLine(testString)); 

     foreach (var action in actionList) 
     { 
      action(); 
     } 
    } 
} 

당신이 TestString에두고 있는지 확인 필요,이를 방지하기 위해 처음에 작업 목록에 추가 한 후 변경되지 않고 두 번째 시간을 전달하기 위해 다른 문자열 참조를 사용합니다.

+0

안녕하세요! 이것은 가능한 해결책이지만이 방법을 사용하면 어떻게 반환 값을 얻을 수 있습니까? 예를 들어, Query 또는 Modify 메소드가 동일한 스레드 또는 BackroundWorker 인스턴스에서 호출 된 경우에도 데이터를 사용하려고합니다. – user1802693

+0

동작 대신 Func 을 사용할 수 있습니다. 이렇게하면 다른 스레드의 코드가 호출 된 호출에서 반환 된 값을 가져올 수 있습니다. 그러면 모든 호출이 '객체'를 반환합니다. 그러면 객체를 사용하기 위해 필요한대로이 객체를 캐스팅해야합니다. – Baldrick