我有以下代码:
string commandText = await _client
.GetCommandTextAsync("Products", x.ProductName == "Chai");
第二个参数 (x.ProductName == "Chai") 包含一个动态子句 (x.ProductName),因此生成的表达式也是动态的。这段代码在.NET 4.0 上执行时,有时会抛出如下异常:
System.InvalidCastException Unable to cast object of type 'System.Runtime.CompilerServices.TaskAwaiter`1[System.String]' to type 'System.Runtime.CompilerServices.INotifyCompletion'.
如果我显式地将方法结果传递给任务,则不会抛出异常:
string commandText = await (Task<string>)_client
.GetCommandTextAsync("Products", x.ProductName == "Chai");
是否有更优雅的方法来解决此问题(无需强制转换等待动态结果的每一行代码),或者这是在 .NET 4.0 上使用 TPL 的已知问题。
我在 .NET 4.5 上没有遇到过这种情况。
最佳答案
这是一个理论:
根据TaskAwaiter定义:
[HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
public struct TaskAwaiter : ICriticalNotifyCompletion, INotifyCompletion
TaskAwaiter 似乎是一个INotifyCompletion。你说你的代码中有 dynamic 子句。正如 MS 所述,动态 对象大多表现得像对象。因此,在由运行时或编译器处理的代码中需要强制转换。
您还表示该平台是 Xamarin iOS。例如,可能利用 HostProtectionAttribute 来阻止某些类等的使用。
TaskAwaiter 实现被标记为 SecurityAction.LinkDemand,如果我们再次检查 MSDN它说:
...
LinkDemand (do not use in the .NET Framework 4)
...
因此结论是:运行代码的平台缺乏主机保护所需的安全实现,并且未调用方法(而安全性未正常工作)转换是“安全”操作之一,因此这种类型的运行时转换失败.
如果您像以前那样显式转换,则没有问题,因为编译器不会添加“错误”代码。
关于c# - 等待带有动态参数的方法时抛出异常(有时),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23033731/