我的问题与这些问题有点类似:
replay a list of functions and parameters
C# delegate for two methods with different parameters
我的目标是将函数调用及其参数存储在列表中,以便在我的经理类调度的不同线程中调用它们。
例如,我想打电话给那样的语句:
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)..我怎样才能找回我的返回值?
我认为,我不能以这种方式使委托通用,我可以用它来存储具有不同签名的方法..
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 :(得分:0)
我会使用这种模式:
ServerManager.addDoSomething(() => ServerManager.SERVICES.Logout());
ServerManager.addDoSomething(() => ServerManager.SERVICES.Modify (searchExpr, newVal));
只存储一个简单的Action。您可以对所有这些模式使用此模式,因为提供的参数将由闭包捕获,因此您无需担心单独保存它们。
下面的简单示例演示了我的意思:
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之前,需要注意。如果这样做,Action中使用的值也将被修改(闭包抓取引用)。
举个例子:
下面的代码输出'Test 2'两次,因为在执行Actions之前更改了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添加到操作列表后保持不变,并使用不同的字符串引用进行第二次传递。