2010-01-08 5 views
5

je la déclaration de classe suivante:Pourquoi C# ne supporte-t-il pas un objet avec une interface en paramètre?

public class EntityTag : BaseEntity, ITaggable 

J'ai une méthode d'aide Html:

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

Ceci est mon 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") %> 

Lorsque je passe une collection IQueryable à l'ascx, j'obtiens cette erreur:

Compil Message d'erreur: CS1928: 'System.Web.Mvc.HtmlHelper>' ne contient pas de définition pour 'TagCloud' et la meilleure méthode de surcharge 'EDN.MVC.Helpers.EdnHelpers.TagCloud (System.Web.Mvc.HtmlHelper, System.Linq.IQueryable, int, string) » a des arguments invalides

Si je tente de convertir explicitement la collection d'objets avec ceci:

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

je reçois la même erreur - les valeurs que je suis de passage dans ne sont pas aimés par le compilateur.

Mon classe EntityTag ne devrait-elle pas automatiquement être prise en charge en tant que IQueryable? Qu'est-ce que je rate? Ça doit être quelque chose d'évident. (Je l'espère).

+0

ITaggable hérite-t-il de IQueryable? –

+0

Quel est le paramètre du modèle que vous passez? Je devine que ce paramètre ne peut pas être converti en IQueryable, pour une raison quelconque. –

+0

Tony: EntityTag descend de BaseEntity et implémente ITaggable –

Répondre

5

Essentiellement, vous essayez de passer un objet du type non générique IQueryable à une méthode qui accepte le IQueryable<ITaggable> générique, que le compilateur ne peut pas « match », ce qui dans le CS1928 (puisque les deux types sont, en fait, différents).

Dans votre surcharge qui accepte un IQueryable<object> (qui fait déjà la conversion nécessaire à une liste générique), il vous suffit d'appeler la version générique de AsQueryable au lieu de celui non générique, comme tel:

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

Permettez-moi d'ajouter, ainsi que IQueryable<T> dérive de IQueryable, ce qui signifie sont pas tous IQueryable<T>IQueryable objets, rendant ainsi la conversion nécessaire. Si la situation était inversée, c'est-à-dire votre méthode d'assistance "réelle" a été définie pour gérer IQueryable objets, alors vous n'auriez aucun problème à passer un IQueryable<T> à cette méthode (puisque tous les objets IQueryable<T> sont, en fait, IQueryable). Par Craig Stuntz, une solution beaucoup plus élégante utilisant les caractéristiques de LINQ: <%= Html.TagCloud(Model.Select(t => (ITaggable)t), 6, "entity-tags") %>

Vous pouvez également utiliser <%= Html.TagCloud(Model.Cast<ITaggable>(), 6, "entity-tags") %> si votre fournisseur interrogeable le prend en charge.

+1

Ceci est juste en ce qui concerne la cause (+1), mais j'utiliserais une solution plus simple: '<% = Html.TagCloud (Model.Select (t => (ITaggable) t), 6, "entity-tags")%> '. Vous pouvez également utiliser 'IEnumerable .Cast()' si votre fournisseur interrogeable le prend en charge. –

+0

Merci pour la réponse. Malheureusement, la deuxième version n'est jamais sélectionnée par le compilateur lorsque la version basée sur l'interface est également déclarée, même si je lance l'ascx. Cela me semble encore étrange que le compilateur ne puisse pas déterminer que EntityTag a l'interface ITaggable, cependant. Pour résumer, je suis toujours à la recherche d'une solution raisonnable ... –

+0

Merci, Craig - c'est le genre de solution de casting que je cherchais car le compilateur ne lance pas automatiquement pour moi. Ça a marché. Si vous convertissez votre commentaire en réponse, je l'accepterai comme solution. –

1

Votre EntityTag classe est IQueryable, mais le compilateur ne sait pas que votre liste de balises est en fait une liste des EntityTag objets, il sait seulement qu'il est une liste d'objets d'application ITaggable, qui ISN probablement 't IQueryable.

2

C# 4.0 le supportera. Chercher « Covariance et Contravariance en C# 4 »

Questions connexes