I have the following class declaration:
public class EntityTag : BaseEntity, ITaggable
I have an Html helper method:
public static string TagCloud(this HtmlHelper html, IQueryable<ITaggable> taggables,
int numberOfStyleVariations, string divId)
This is my ASP.NET MVC ascx:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IQueryable<EDN.MVC.Models.EntityTag>>" %>
<%@Import Namespace="EDN.MVC.Helpers" %>
<%= Html.TagCloud(Model, 6, "entity-tags") %>
When I pass in an IQueryable collection to the ascx, I get this error:
Compiler Error Message: CS1928: ‘System.Web.Mvc.HtmlHelper>’ does not contain a definition for ‘TagCloud’ and the best extension method overload ‘EDN.MVC.Helpers.EdnHelpers.TagCloud(System.Web.Mvc.HtmlHelper, System.Linq.IQueryable, int, string)’ has some invalid arguments
If I try to explicitly convert the object collection with this:
public static string TagCloud(this HtmlHelper html, IQueryable<Object> taggables, int numberOfStyleVariations, string divId)
{
var tags = new List<ITaggable>();
foreach (var obj in taggables)
{
tags.Add(obj as ITaggable);
}
return TagCloud(html, tags.AsQueryable(), numberOfStyleVariations, divId);
}
I get the same error – the values I’m passing in are not liked by the compiler.
Shouldn’t my EntityTag class automatically be supported as IQueryable? What am I missing? It’s got to be something obvious. (I hope.)
Essentially, you’re trying to pass an object of the non-generic type
IQueryableto a method that accepts the genericIQueryable<ITaggable>, which the compiler cannot “match”, resulting in the CS1928 (since the two types are, in fact, different).In your overload that accepts an
IQueryable<object>(which is already doing the necessary conversion to a generic list), you simply need to call the generic version ofAsQueryableinstead of the non-generic one, as such:Allow me to add, as well, that
IQueryable<T>derives fromIQueryable, meaning that not allIQueryableobjects areIQueryable<T>, thus making the conversion necessary. If the situation were reversed, i.e. your “real” helper method was defined to handleIQueryableobjects, then you certainly would have no problem passing anIQueryable<T>to that method (since allIQueryable<T>objects are, in fact,IQueryable).Per Craig Stuntz, a much more elegant solution using LINQ features:
<%= Html.TagCloud(Model.Select(t => (ITaggable)t), 6, "entity-tags") %>. You can also use<%= Html.TagCloud(Model.Cast<ITaggable>(), 6, "entity-tags") %>if your queryable provider supports it.