我有一个创建计时器的循环。我有2个问题。
第一个问题是如何将命令作为“发射并忘记”运行,因此我可以调用它,它将在另一个线程中自行执行,它将自行回发给API。如果refresh属性设置为0,则会出现这种情况。
第二个是循环中的参数(check.key)在循环的下一次迭代中被替换。当委托触发方法时,它会传递替换值,而不是原始分配!!!
在下面的示例中,值被正确分配,但是当委托触发时,它总是使用参数“3”触发。
Dictionary _mydict充满了来自远程API的数据。
classtocall和methodtocall不会总是一样的。它们可以被多次调用 - 因为提供的密钥可以访问Test类中的更多参数。 Test类中的refresh属性定义了计时器时间。
我希望这是有道理的!
代码(快速模型,因为我的真实代码很大):
public class Test
{
public string ClassToCall;
public string MethodToCall;
public string UniqueKey;
public long Refresh;
// more but removed for sample
public Test(string MyClass, string MyMethod, string Key)
{
this.ClassToCall = MyClass;
this.MethodToCall = MyMethod;
this.UniqueKey = Key;
}
}
class runme
{
public static void runmefirst(string Key)
{// Does some processing based on Key
}
public static void runmesecond(string Key)
{ // Does some processing based on Key
}
public static void runmelast(string Key)
{ // Does some processing based on Key
}
}
class myclass
{
private static Timer[] timers;
static void Main()
{
Dictionary<string, Test> _mydict = new Dictionary<string, Test>();
_mydict.Add("1", new Test("runme", "runmefirst", "1"));
_mydict.Add("2", new Test("runme", "runmesecond", "2"));
_mydict.Add("3", new Test("runme", "runmelast", "3"));
int i = 0;
foreach (KeyValuePair<string,Test> check in _mydict)
{
Type t = Type.GetType(check.Value.ClassToCall);
if (t != null)
{
MethodInfo mi = t.GetMethod(check.Value.MethodToCall);
if (mi != null)
{
if (check.Value.Refresh == 0)
{
mi.Invoke(null, new string[] { check.Key }); // << problem 1: need this fire and forget!
}
else
{
myclass.timers[i] = new Timer(
delegate { mi.Invoke(null, new string[] { check.Key }); }, // << problem 2: when called, check.Key is always last value in loop
null,
i * 1000,
check.Value.Refresh * 5000
);
}
}
}
i+=1;
}
}
}
由于
答案 0 :(得分:0)
对于计时器部分:
您尚未显示您正在使用哪种Timer
(有三种)。如果您正在使用System.Threading.Timer
或System.Timers.Timer
,那么我希望它已经在线程池上执行...
对于错误的值部分:
你正在使用循环:
foreach (KeyValuePair<string,Test> check in _mydict)
然后你用匿名方法捕获check
:
delegate { mi.Invoke(null, new string[] { check.Key }); },
捕获变量 check
,check
的值在每次迭代时都会发生变化。您将始终看到最后一个值。这个很容易修复:
foreach (KeyValuePair<string,Test> check in _mydict)
{
var copy = check;
...
// Then later...
delegate { mi.Invoke(null, new string[] { copy.Key }); },
}
这次你将在每次迭代中捕获一个“新的”局部变量,并且该局部变量的值不会改变。
请注意,行为将在C#5中更改,以允许您以前的代码在此处工作。
另一方面,您可以使用Delegate.CreateDelegate
直接从MethodInfo
创建委托,并将其传递给...
答案 1 :(得分:0)
开始一个新线程
System.Threading.Thread mythread =
new System.Threading.Thread(new System.Threading.ThreadStart(MyFunction));
mythread .Start();
名为
的函数private void MyFunction()
{
if (InvokeRequired)
{
this.Invoke(new MethodInvoker(MyFunction));
return;
}
//DO YOUR STUFF
}