CastException 尝试调用 Action> 异步委托
我似乎无法弄清楚为什么我在运行以下代码时遇到 InvalidCastException:
var item = new KeyValuePair<string, string>("key", "value");
Action<KeyValuePair<string, string>> kvrAction =
kvr =>Console.WriteLine(kvr.Value);
var result = kvrAction.BeginInvoke(item, null, null);
kvrAction.EndInvoke(result);
异常信息:
Test method Utilities.Tests.IEnumerableExtensionTests.ProveDelegateAsyncInvokeFailsForKeyValuePair threw exception: System.Runtime.Remoting.RemotingException: The argument type '[key, value]' cannot be converted into parameter type 'System.Collections.Generic.KeyValuePair`2[System.String,System.String]'.
---> System.InvalidCastException: Object must implement IConvertible..
任何帮助将不胜感激=)此代码似乎适用于我抛出的任何东西,除了 KeyValuePair<>。
更新:似乎任何结构都存在这种情况。 我没有注意到 KeyValuePair<> 是一个结构体,因此仅使用类进行测试。 我仍然不明白为什么会这样。
更新 2:Simon 的回答有助于确认这种行为是意外的,但是实现自定义类型不适用于我想要做的事情。 我正在尝试在 IEnumerable<> 上实现扩展方法 为每个项目异步执行委托。 我注意到针对通用 Dictionary 对象运行测试时出错。
public static IEnumerable<T> ForEachAsync<T>(this IEnumerable<T> input, Action<T> act)
{
foreach (var item in input)
{
act.BeginInvoke(item, new AsyncCallback(EndAsyncCall<T>), null);
}
return input;
}
private static void EndAsyncCall<T>(IAsyncResult result)
{
AsyncResult r = (AsyncResult)result;
if (!r.EndInvokeCalled)
{
var d = (Action<T>)((r).AsyncDelegate);
d.EndInvoke(result);
}
}
我宁愿不使用 T 上的约束来限制该方法,以确保仅使用类,因此我按如下方式重构了该方法,以解决 BeginInvoke 的问题,但我之前没有直接使用过 TreadPool,并且想确保我我没有错过任何重要的事情。
public static IEnumerable<T> ForEachAsync<T>(this IEnumerable<T> input, Action<T> act)
{
foreach (var item in input)
ThreadPool.QueueUserWorkItem(obj => act((T)obj), item);
return input;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
奇怪的是,似乎是.NET(C#?)中将参数编组到工作线程时出现的某种错误。
如果您在传递的结构上实现 IConvertable:
它运行良好。 传递的 conversionType 不会传递 .Equal()、IsAssignableFrom() 或我尝试过的任何其他内容(除了 GUID 比较),这可能与它首先要求 IConvertable 的原因有关。
编辑:一个简单的解决方法是使用闭包来传递参数:
当然,如果您需要结果,则需要存储 IAsyncResults,这可能与另一个方向的参数有相同的问题。 作为替代方案,您可以在完成后将它们添加到集合中,但锁定会有点奇怪:
Odd, seems to be some sort of bug in .NET (C#?) with marshalling the argument to the worker thread.
If you implement IConvertable on the passed struct:
It runs fine. The passed conversionType doesnt pass .Equal(), IsAssignableFrom(), or anything else I tried except GUID comparison, which is probably related to why it asks for an IConvertable in the first place.
EDIT: A simple workaround is to use closures to pass the parameter:
Of course, if you need the results, you will need to store the IAsyncResults, which will probably have the same issue as parameters, in the other direction. As an alternative, you could add them to a collection when they are complete, but the locking gets a bit weird: