Cannot use a lambda expression as an argument to a dynamically dispatched operation

Since the introduction of the Web Pages framework, ASP.NET has been making use of the dynamic type introduced in C# 4.0. Along with that comes some new error messages which at first glance don't make a lot of sense - mainly because they are unexpected. I have already looked at how dynamics do not support extension methods, and a recent question in the ASP.NET forums illustrated another way in which the dynamic type can catch you out.

The full text of the error message was

Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type 

The code that caused this compilation error looked something like this:

var db = Database.Open("Northwind");
var category = db.QueryValue("SELECT CategoryId FROM Categories WHERE CategoryName = 'Beverages'");
var products = db.Query("SELECT ProductId, ProductName FROM Products WHERE CategoryId = @0", category);
var selectListItems = products.Select(i => new SelectListItem { //error here
    Value = i.ProductId.ToString(), 
    Text = i.ProductName
});

This is illustrative only, so disregard the fact that the two SQL statements can be merged into one.

The error was raised at the point where the questioner attempted to project the results of the second query (variable products) into a new form - an Enumerable<SelectListItem> - in preparation for an HTML DropDown helper. The projection was being attempted through the use of the Enumerable.Select method that takes a delegate represented as a lambda expression. But where is the "dynamically dispatched operation" that doesn't like lambda expressions? The return type from a Database.Query method call is an IEnumerable, not a dynamic type. However, the return type of the Database.QueryValue method is a dynamic. At the moment this isn't clear from the documentation on MSDN, which says that the return type is System.Object. It also inn't clear from WebMatrix, where "IntelliSense" in version 2 is little more than a code completion tool, and doesn't offer any information on compiler errors. However, it is clear from Visual Studio (Express) if you hover over the var keyword:

So how does that affect the products variable? Well, the thing about dynamic is that any operation that it is involved in will be resolved at runtime. In other words, they become dynamic too. And this can be evidenced by hovering over the var keyword relating to the products variable. In other words, the return type of the Database.Query call is no longer an IEnumerable. It's a dynamic:

An interesting thing about dynamic - you can pass one in as an argument to pretty much any method as a parameter. As soon as you do of course, the return type of the method changes to dynamic.

A lambda needs to know the data type of the parameter at compile time. It doesn't like parameters whose type will be resolved at runtime. It needs to be able to infer what type i is in the example above. The advice given in the error message is somewhat typical of .NET error messages that require a ton of research to become clear. However, the solution to the problem is a lot more straightforward. Just as you can pass a dynamic as an argument to any method, you can cast a dynamic to any type. The compiler will happily trust what you are doing and leave it up to the DLR (Dynamic Language Runtime) to complain vigorously if the type you have specified for your dynamic is unnacceptable in the context in which you have tried to use it.

In the case above, you can simply explicitly specify category as an int. Object and string will do just as well in this context, as the value will be passed in to a SQL command as a parameter value - and they are always sent as strings over the wire:

var db = Database.Open("Northwind");
int category = db.QueryValue("SELECT CategoryId FROM Categories WHERE CategoryName = 'Beverages'");
var products = db.Query("SELECT ProductId, ProductName FROM Products WHERE CategoryId = @0", category);
var selectListItems = products.Select(i => new SelectListItem { 
    Value = i.ProductId.ToString(), 
    Text = i.ProductName
});

Or you can opt to force the return type of the Database.Query method to an Enumerable:

var db = Database.Open("Northwind");
var category = db.QueryValue("SELECT CategoryId FROM Categories WHERE CategoryName = 'Beverages'");
IEnumerable<dynamic> products = db.Query("SELECT ProductId, ProductName FROM Products WHERE CategoryId = @0", category);
var selectListItems = products.Select(i => new SelectListItem {
    Value = i.ProductId.ToString(), 
    Text = i.ProductName
});

Either way, the error goes away as the type is now known to the compiler.

So far, I have looked at the WebMatrix data access library, which features a lot of use of the dynamic type. It is also used within the Web Pages framework to provide a storage and access mechanism for the App and Page properties, which allow you to access AppState and PageData entries using dot notation as if they were properties of a class. There are other areas in ASP.NET that make use of dynamics - in particular the ViewBag property that was introduced in MVC 3. This kind of code has already been posted to forums with the same compiler error being reported:

var CountrySelectList = ViewBag.Countries.Select(c => new SelectListItem {
    Value = c.CountryId.ToString(),
    Text = c.CountryName
});

Again, ignoring whether this is fundamentally a good approach, whatever is stored in ViewBag.Countries is a dynamic type. So it needs to be cast to an appropriate type for the operation:

var CountrySelectList = ((IEnumerable<Country>)ViewBag.Countries).Select(c => new SelectListItem {
    Value = c.CountryId.ToString(),
    Text = c.CountryName
});

The dynamic type provides a lot of flexibility and a nice syntax for accessing arbitrary values that might otherwise require dictionaries for storage. But as you have seen, dynamic re-writes some of the rules that you are used to when working with static type checking. So long as you are aware where dynamic is used in Web Pages and MVC, you should be able to avoid the pitfalls.

 

Date Posted: Tuesday, September 18, 2012 8:08 AM
Last Updated:
Posted by: Mikesdotnetting
Total Views to date: 24978

1 Comment

Thursday, January 3, 2013 4:46 PM - angel

I got this same error but in my case there was a typo in the line that declared the @model in my view. Once I removed the extraneous text, the error went away.
Add your comment

If you have any comments to make about this article, please use this form to do so. Make sure that your comment relates specifically to the article above. More general comments can be posted through the form on the Contact page.

Please note, all comments are moderated, and some may not be published. The kind of things that will ensure your comment is deleted without ever seeing the light of day are as follows:

  • Not relevant to the article
  • Gratuitous links to your own site or product
  • Anything abusive or libellous
  • Spam
  • Anything in a language I don't understand including gibberish.

I do not pass email addresses on to spammers, so a valid one will assist me in responding to you personally if required.

Recent Comments

Bino 11/27/2014 7:05 PM
In response to MVC 5 with EF 6 in Visual Basic - Async and Stored Procedures with the Entity Framework
Copy +...

Manas 11/27/2014 5:30 AM
In response to Scheduled Tasks In ASP.NET With Quartz.Net
Hi Mike, Thank you for awesome article. My concern is it might impact website if we use or is...

priya 11/26/2014 6:50 PM
In response to Create PDFs in ASP.NET - getting started with iTextSharp
very nice.....its save my time...

ransems 11/24/2014 12:29 AM
In response to Adding A Controller
Love the article. I dislike that the world thinks c# articles are the way to go. Love the VB, keep...

Gautam 11/20/2014 8:01 AM
In response to I'm Writing A Book On WebMatrix
Hello Mike, I read your book, loved it! However, I have a few request/suggestions: 1) an example...

Bret Dev 11/19/2014 8:39 PM
In response to The Difference Between @Helpers and @Functions In WebMatrix
Excellent post! One concern - where can you place global @Functions code within an MVC project to Is...

Rob Farquharson 11/19/2014 4:28 PM
In response to iTextSharp - Links and Bookmarks
How can I place text at an absolute position on the page? Also, how can I rotate text?...

Andy 11/17/2014 8:08 PM
In response to MVC 5 with EF 6 in Visual Basic - Sorting, Filtering and Paging
Hello I'm testing your sorting instructions above. This is great and I was able to get it to work...

Gautam 11/17/2014 5:51 PM
In response to WebMatrix - Database Helpers for IN Clauses
Hi Mike, I am very new to programming: In the above example if I want to use a delete button the...

donramon 11/17/2014 3:22 PM
In response to Entity Framework 6 Recipe - Alphabetical Paging In ASP.NET MVC
Congratulations on your new website look and the excellent articles. Thank you!...