动态对象的奇怪行为
Strange behavior of dynamic objects
我有一个简单的控制方法 DoSomething
,它接收 json 字符串,将其转换为动态对象并尝试获取数据:
[HttpPost]
public string DoSomething(string jsonStr) // {"0":null,"1":"loadData"}
{
// In this case obj.GetType() = System.Web.Helpers.DynamicJsonObject
object obj = Json.Decode(jsonStr);
// Correct, a == "loadData"
var a = (obj as dynamic)["1"];
// Incorrect, compilation exception:
// "Cannot apply indexing with [] to an expression
// of type 'System.Web.Helpers.DynamicJsonObject'"
var b = (obj as DynamicJsonObject)["1"]
return "OK";
}
我的问题是为什么在原始类型没有索引器的情况下将对象用作动态对象时可以访问索引器?
在第一种情况下,您正在使用 dynamic
的所有基础设施 - 它不仅使用反射来查找 "real" 成员,还使用 IDynamicMetaObjectProvider
提供支持仅在执行时已知的成员。这是可行的,因为当您使用 dynamic
时,绑定过程(确定成员名称的含义)是在执行时而不是编译时执行的。
在这种情况下,它是在执行时使用的索引器 - DynamicJsonObject
没有声明索引器,但覆盖了 DynamicObject
的 TryGetIndex
方法。 DynamicObject
的元对象提供程序实现将通过 TryGetIndex
.
路由索引器 "get" 调用
一个更简单的例子是 ExpandoObject
:
ExpandoObject foo = new ExpandoObject();
// This is invalid; the compiler can't find a Property member
foo.Property = "broken";
dynamic bar = foo;
// This is fine; binding is performed at execution time.
bar.Property = "working";
我有一个简单的控制方法 DoSomething
,它接收 json 字符串,将其转换为动态对象并尝试获取数据:
[HttpPost]
public string DoSomething(string jsonStr) // {"0":null,"1":"loadData"}
{
// In this case obj.GetType() = System.Web.Helpers.DynamicJsonObject
object obj = Json.Decode(jsonStr);
// Correct, a == "loadData"
var a = (obj as dynamic)["1"];
// Incorrect, compilation exception:
// "Cannot apply indexing with [] to an expression
// of type 'System.Web.Helpers.DynamicJsonObject'"
var b = (obj as DynamicJsonObject)["1"]
return "OK";
}
我的问题是为什么在原始类型没有索引器的情况下将对象用作动态对象时可以访问索引器?
在第一种情况下,您正在使用 dynamic
的所有基础设施 - 它不仅使用反射来查找 "real" 成员,还使用 IDynamicMetaObjectProvider
提供支持仅在执行时已知的成员。这是可行的,因为当您使用 dynamic
时,绑定过程(确定成员名称的含义)是在执行时而不是编译时执行的。
在这种情况下,它是在执行时使用的索引器 - DynamicJsonObject
没有声明索引器,但覆盖了 DynamicObject
的 TryGetIndex
方法。 DynamicObject
的元对象提供程序实现将通过 TryGetIndex
.
一个更简单的例子是 ExpandoObject
:
ExpandoObject foo = new ExpandoObject();
// This is invalid; the compiler can't find a Property member
foo.Property = "broken";
dynamic bar = foo;
// This is fine; binding is performed at execution time.
bar.Property = "working";