2010-01-08 16 views
5

Tengo la siguiente declaración de la clase:¿Por qué c no admite un objeto con una interfaz como parámetro?

public class EntityTag : BaseEntity, ITaggable 

tengo un método de ayuda HTML:

public static string TagCloud(this HtmlHelper html, IQueryable<ITaggable> taggables, 
    int numberOfStyleVariations, string divId) 

Esta es mi ascx ASP.NET MVC:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IQueryable<EDN.MVC.Models.EntityTag>>" %> 
<%@Import Namespace="EDN.MVC.Helpers" %> 
<%= Html.TagCloud(Model, 6, "entity-tags") %> 

Cuando paso en una colección de IQueryable para el ascx, obtengo este error:

Compil er Mensaje de error: CS1928: 'System.Web.Mvc.HtmlHelper>' no contiene una definición para 'TagCloud' y la mejor sobrecarga del método de extensión 'EDN.MVC.Helpers.EdnHelpers.TagCloud (System.Web.Mvc.HtmlHelper, System.Linq.IQueryable, int, string)' tiene algunos argumentos no válidos

Si trato de convertir explícitamente la colección de objetos con esto:

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); 
    } 

me sale el mismo error - los valores que estoy pasando en no son del agrado del compilador.

¿No debería mi clase EntityTag ser admitida automáticamente como IQueryable? ¿Qué me estoy perdiendo? Tiene que ser algo obvio. (Espero).

+0

¿ITaggable hereda de IQueryable? –

+0

¿Cuál es el parámetro del modelo que está pasando? Supongo que ese parámetro no se puede convertir a IQueryable, por alguna razón. –

+0

Tony: EntityTag desciende de BaseEntity e implementa ITaggable –

Respuesta

5

En esencia, que está tratando de pasar un objeto del tipo no genérico IQueryable a un método que acepta el genérica IQueryable<ITaggable>, que el compilador no puede "coincidencia", lo que resulta en el CS1928 (ya que los dos tipos son, de hecho, diferentes).

En su sobrecarga que acepta una IQueryable<object> (que ya está haciendo la conversión necesaria a una lista genérica), sólo hay que llamar a la versión genérica de AsQueryable en lugar de uno no genérico, como por ejemplo:

public static string TagCloud(this HtmlHelper html, IQueryable 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<ITaggable>(), numberOfStyleVariations, divId); 
} 

me permite manejar, además, que se deriva de IQueryable<T>IQueryable, lo que significa que no todos los objetos son IQueryableIQueryable<T>, con lo que la conversión necesaria. Si la situación se invirtió, es decir, su método de ayuda "real" se definió para manejar objetos IQueryable, entonces ciertamente no tendría problemas para pasar un IQueryable<T> a ese método (ya que todos los objetos IQueryable<T> son, de hecho,).

Por Craig Stuntz, una solución mucho más elegante que utiliza las características LINQ: <%= Html.TagCloud(Model.Select(t => (ITaggable)t), 6, "entity-tags") %>. También puede usar <%= Html.TagCloud(Model.Cast<ITaggable>(), 6, "entity-tags") %> si su proveedor consultable lo admite.

+1

Esto es correcto con respecto a la causa (+1), pero usaría una solución más simple: '<% = Html.TagCloud (Model.Select (t => (ITaggable) t), 6, "etiquetas de entidad")%> '. También puede usar 'IEnumerable .Cast()' si su proveedor consultable lo admite. –

+0

Gracias por la respuesta. Desafortunadamente, la segunda versión nunca es seleccionada por el compilador cuando la versión basada en la interfaz también es declarada, incluso si lanzo el archivo ascx. Todavía me parece tan peculiar que el compilador no puede determinar si EntityTag tiene la interfaz ITaggable. En resumen, sigo buscando una solución razonable ... –

+0

Gracias, Craig, ese es el tipo de solución de casting elegante que estaba buscando ya que el compilador no me emite automáticamente. Eso funciono. Si convierte su comentario en una respuesta, lo aceptaré como la solución. –

1

Su clase EntityTag es IQueryable, sin embargo, el compilador no sabe que su lista de etiquetas es en realidad una lista de EntityTag objetos, sólo se sabe que se trata de una lista de objetos de aplicación ITaggable, lo que probablemente ISN 't IQueryable.

2

C# 4.0 lo admitirá. Búsqueda de "Covarianza y contravarianza en C# 4"

Cuestiones relacionadas