2013-11-23 123 views
0

我的问题有点类似这些问题:延迟方法调用使用委托

replay a list of functions and parameters

C# delegate for two methods with different parameters

我的目标是存储与它们在列表中的参数函数调用,调用他们一个不同的线程,由我的经理级别安排。

  • 当函数被调用时,其自身添加到的记住参数的功能列表和值
  • 当函数结束时,我想找回返回对象(如果有的话)
  • 允许在功能列表中,以在以后的时间被称为
  • 有不同的方法,用完全不同的签名 (他们中的一些有返回值(BOOL,INT,对象..),他们中的一些已经没有了,而的方法的参数数目是不固定的)

例如我想调用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使用,用户名,密码));

或者什么支持接口其他方式..

应该怎样我ServerManager.addDoSomething方法(或者,如果签名不同的方法)变成什么样子,什么样的数据结构,我应该使用(WHAT_SHOULD_I_STORE),如果我想要支持延迟的函数调用..我怎样才能找回我的返回值?

我想,我不能让代表一般以这种方式,我可以用它来storeing具有不同签名的方法..

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

我的课:

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

我会使用这种模式:

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

唯一需要注意的是,你需要的,如果你改变你逝去的当您添加它后一个方法参数的对象要小心,但你之前从列表中调用您的操作。如果这样做,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 而不是Action - 这将允许您的另一个线程上的代码获取来自任何调用的调用的返回值。每次调用都会返回一个'对象' - 然后您必须根据需要投射这些对象才能使用它们。 – Baldrick