Liming
Liming

Reputation: 1661

DynamicObject? How does the following code work?

I just can't seem to piece the following code together in the source code of MVC Webgrid.

When we are constructing the grid column, we do say

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

"item" is a lambda parameter obviously and it's actually a "WebGridRow" class. (I THINK!! UNLESS I'm WRONG) See source code here

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

My issue here is, "Id" is not a property of this class and since WebGridRow inherits from DynamicObject, how exactly the ".Id" property mapped to the "source object" of the current row?

Btw, the source object "object value" is passed through the constructor of WebGridRow

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

Column definition

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

Column is invoked in "WeBGridRenderer" class as

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

Finally, the "Format" function in "WeBGridRenderer"

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

Upvotes: 2

Views: 589

Answers (2)

Alxandr
Alxandr

Reputation: 12423

[Edit]
I've written a fairly extensive blog-post on the subject over here: http://blog.alxandr.me/2013/07/26/dynamic-dispatch-how-dynamic-work-in-c/ If you are interested in how dynamic dispatch in C# works, this might explain quite a bit.
[/Edit]

I've worked a lot with the DLR, and it's a huge and complicated beast, but I'll try to keep this simple.

What happens when you do anything with a dynamic in C# is that the compiler generates a dynamic call-site. If you decompile the code you'd end up with something like CallSite<Func<CallSite, object, object, object>> in most cases (not functions, they tend to have more than 2 parameters). The call-site does a lot of magic that we don't need to get too much into, but when an object implements IDynamicMetaObjectProvider the dynamic callsite (or the binder used rather) invokes GetMetaObject (http://msdn.microsoft.com/en-us/library/system.dynamic.idynamicmetaobjectprovider.getmetaobject.aspx) on said object.

A DynamicMetaObject's role is to describe how to perform dynamic operations against a given object. In your case, the dynamic operation is "read property named Id", so the callsite calls BindGetMember on the dynamic meta object. This BindGetMember can do anything it likes, however, in the case of DynamicObject it calls TryGetMember on the DynamicObject itself.

Now, there's a lot of caching (and black magic) involved, that makes this efficient, and DynamicObject provides a simple way to implement IDynamicMetaObjectProvider (which can be a real beast to get right at times), but that still doesn't mean that every dynamic object is a DynamicObject.

For instance, if I do this:

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

test (which is obviously a string) has no method TryGetMember. However the CSharpGetMemberBinder knows how to use reflection to figure out that string has a property named Length and return that.

Upvotes: 7

Jon
Jon

Reputation: 437336

When you try to access a property on a DynamicObect, the DLR calls its TryGetMember method at runtime (see how WebGridRow implements it). What you get back is that method's result, provided through its out parameter.

A most important detail here is that your lambda function argument item is not typed as WebGridRow -- in that case this code would not compile. Dynamism is achieved because the signature of WebGrid.Column declares the format parameter as a Func<dynamic, object> -- it's the dynamic type of the argument that allows the DLR to take over.

Upvotes: 3

Related Questions