DynamicObject?以下代码如何工作?

时间:2013-07-26 07:42:22

标签: c#

我似乎无法在MVC Webgrid的源代码中将以下代码拼凑在一起。

当我们构建网格列时,我们会说

grid.Column("Id", format: (item) => item.GetSelectLink(item.Id)),

“item”显然是一个lambda参数,它实际上是一个“WebGridRow”类。 (我认为!!除非我错了)请参阅此处的源代码

https://github.com/mono/aspnetwebstack/blob/master/src/System.Web.Helpers/WebGrid/WebGridRow.cs

我的问题是,“Id”不是此类的属性,并且由于WebGridRow继承自DynamicObject,“。Id”属性究竟是如何映射到当前行的“源对象”的?

顺便说一句,源对象“对象值”通过WebGridRow的构造函数传递

public WebGridRow(WebGrid webGrid, object value, int rowIndex)
{
    _grid = webGrid;
    _value = value;
    _rowIndex = rowIndex;
    _dynamic = value as IDynamicMetaObjectProvider;
}

列定义

public Func<dynamic, object> Format { get; set; }

在“WeBGridRenderer”类中调用列为

 foreach (var row in webGrid.Rows)
 {
                     .....
                    foreach (var column in columns)
                    {
                        var value = ...Format(column.Format, row).ToString();
                        ...
                    }
 }

最后,“WeBGridRenderer”中的“格式”功能

private static HelperResult Format(Func<dynamic, object> format, dynamic arg) {
        var result = format(arg);
        ....
}

2 个答案:

答案 0 :(得分:6)

<强> [编辑]
我在这里写了一篇关于这个主题的相当广泛的博客文章:http://blog.alxandr.me/2013/07/26/dynamic-dispatch-how-dynamic-work-in-c/ 如果您对C#中的动态调度如何工作感兴趣,这可能会解释相当多 的 [/编辑]

我在DLR上做了很多工作,这是一个庞大而复杂的野兽,但我会尽量保持这个简单。

当您在C#中使用dynamic执行任何操作时,会发生什么,编译器会生成动态调用站点。如果您对代码进行反编译,那么在大多数情况下,您最终会得到类似CallSite<Func<CallSite, object, object, object>>的内容(而不是函数,它们往往会有超过2个参数)。调用站点做了很多我们不需要过多的魔术,但是当一个对象实现IDynamicMetaObjectProvider时,动态调用点(或者使用的绑定器)会调用GetMetaObject({{ 3}})对所说的对象。

DynamicMetaObject的作用是描述如何对给定对象执行动态操作。在您的情况下,动态操作是“读取属性名为Id”,因此调用点在动态元对象上调用BindGetMember。这个BindGetMember可以执行任何喜欢的操作,但是,DynamicObject会在TryGetMember上调用DynamicObject

现在,涉及到很多缓存(和黑魔法),这使得效率更高,DynamicObject提供了一种实现IDynamicMetaObjectProvider的简单方法(可以成为真正的野兽)时间),但这并不意味着每个dynamic对象都是DynamicObject

例如,如果我这样做:

dynamic test = "test";
int length = test.Length;

test(显然是一个字符串)没有方法TryGetMember。但是CSharpGetMemberBinder知道如何使用反射来确定string有一个名为Length的属性并返回该属性。

答案 1 :(得分:3)

当您尝试访问DynamicObect上的媒体资源时,DLR会在运行时调用其TryGetMember方法(请参阅how WebGridRow implements it)。您得到的是该方法的结果,通过其out参数提供。

这里最重要的细节是你的lambda函数参数item没有输入WebGridRow - 在这种情况下,这段代码不能编译。动态是因为WebGrid.Column的签名将format参数声明为Func<dynamic, object> - 它是允许DLR接管的参数的dynamic类型。