[英]Unpredictible behaviour in c# dynamic
我在C#中学习动态时发现了一个错误(功能?)。 任何人都可以解释我,为什么我有例外?
static class Program
{
public static void Main(string[] args)
{
dynamic someObj = ConstructSomeObj((Action)(() => Console.WriteLine("wtf")));
var executer = someObj.Execute;
executer(); // shows "wtf"
someObj.Execute(); // throws RuntimeBinderException
Console.ReadKey();
}
static dynamic ConstructSomeObj(dynamic param)
=> new { Execute = param };
}
注意:exectuer和someObj的type都是动态的
我们来看下面的代码:
using System;
using System.Collections.Generic;
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("first");
// works perfectly!!!
dynamic foo = new { x=(Action)(() => Console.WriteLine("ok")) };
foo.x();
// fails
dynamic foo2 = new { x=(object)(Action)(() => Console.WriteLine("ok2")) };
foo2.x();
}
}
dynamic
使用反射来访问对象的方法和字段,因为它不能知道确切的类型,所以它必须依赖于它所操作的对象中存在的类型信息。
当匿名类型的字段x
被正确键入为委托调用时, foo.x()
起作用,因为动态可以看到该字段值是委托。
当你使用
static dynamic ConstructSomeObj(dynamic param)
{ return new { x = param }; }
创建一个匿名类,你用类型为object
字段x
创建类(动态是幕后的object
)。 当你调用obj.x
动态看到该字段类型是一个object
并且它无需检查该字段指向的确切类型。 并且由于object没有像委托一样的Invoke()
方法,因此抛出异常。 如果将方法参数类型更改为Action
,它将起作用。
我想这个决定检查字段类型而不是字段包含的值类型是为了提供更好的性能。 换句话说,当您检查字段类型时, dynamic
生成的CallSite
类可以被缓存并在以后重用。
参考文献: https : //github.com/mono/mono/blob/ef407901f8fdd9ed8c377dbec8123b5afb932ebb/mcs/class/Microsoft.CSharp/Microsoft.CSharp.RuntimeBinder/Binder.cs
编辑:在单声道上检查这个,有人可以在VS上验证
好的,有趣的。 这两条线将起作用:
Task.Run(someObj.Execute);
((Action)someObj.Execute)();
似乎编译器总是接受动态类型的(),并且在运行时CLR只看起来“一层深”。 因此,您可以通过添加显式强制转换或使用Task.Run()隐式执行强制转换来提供帮助。 如果这是一个功能或错误!? ... 不知道 ;-) ...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.