2010-01-08 7 views
5

Ich habe die folgende Klassendeklaration:Warum unterstützt C# kein Objekt mit einer Schnittstelle als Parameter?

public class EntityTag : BaseEntity, ITaggable 

ich eine HTML-Helfer-Methode haben:

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

Dies ist meine 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") %> 

Als ich in geben eine IQueryable-Sammlung an die Ascx, bekomme ich diesen Fehler:

Compil er Fehlermeldung: CS1928: 'System.Web.Mvc.HtmlHelper>' enthält keine Definition für 'TagCloud' und die beste Erweiterungsmethode 'EDN.MVC.Helpers.EdnHelpers.TagCloud (System.Web.Mvc.HtmlHelper, System.Linq.IQueryable, int, string)‘hat einige ungültige Argumente

Wenn ich versuche, explizit mit diesem die Objektsammlung zu konvertieren:

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

ich den gleichen Fehler - die Werte ich vorbei in sind nicht vom Compiler gefallen.

Sollte meine EntityTag-Klasse nicht automatisch als IQueryable unterstützt werden? Was vermisse ich? Es muss etwas Offensichtliches sein. (Hoffe ich).

+0

erbt ITaggable von IQueryable? –

+0

Was ist der Modellparameter, den Sie weitergeben? Ich vermute, dass Parameter aus irgendeinem Grund nicht in IQueryable konvertiert werden können. –

+0

Tony: EntityTag stammt von BaseEntity ab und implementiert ITaggable –

Antwort

5

Im Grunde versucht man, ein Objekt des nicht-generischen Typs IQueryable ein Verfahren zu übergeben, die die generischen IQueryable<ITaggable> akzeptiert, die der Compiler kann nicht „match“, was in der CS1928 (da die beiden Typen tatsächlich verschieden sind).

In Ihrer Überlastung, die ein IQueryable<object> akzeptiert (die bereits die notwendige Umwandlung in eine generischen Liste zu tun), können Sie einfach die generische Version von AsQueryable anstelle des nicht-generischen anrufen müssen, wie zum Beispiel:

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

Erlauben Sie mir, auch hinzufügen, dass IQueryable<T> von IQueryable ableitet, was bedeutet, dass nicht alle IQueryable Objekte IQueryable<T> sind, so dass die Umwandlung notwendig machen. Wenn die Situation umgekehrt wurde, d. H. Ihre "echte" Hilfsmethode wurde definiert, um IQueryable Objekte zu behandeln, dann hätten Sie sicherlich kein Problem damit, eine IQueryable<T> an diese Methode zu übergeben (da alle IQueryable<T> Objekte tatsächlich IQueryable sind).

Pro Craig Stuntz, eine viel elegantere Lösung mit LINQ-Funktionen: <%= Html.TagCloud(Model.Select(t => (ITaggable)t), 6, "entity-tags") %>. Sie können auch <%= Html.TagCloud(Model.Cast<ITaggable>(), 6, "entity-tags") %> verwenden, wenn Ihr abfragbarer Anbieter dies unterstützt.

+1

Dies ist richtig in Bezug auf die Ursache (+1), aber ich würde eine einfachere Lösung verwenden: '<% = Html.TagCloud (Model.Select (t => (ITaggable) t), 6, "Entity-Tags")%> '. Sie können auch 'IEnumerable .Cast()' verwenden, wenn Ihr abfragbarer Anbieter dies unterstützt. –

+0

Danke für die Antwort. Leider wird die zweite Version niemals vom Compiler ausgewählt, wenn die interface-basierte Version auch deklariert wird, selbst wenn ich in die ascx-Instanz eingreife. Es kommt mir immer noch seltsam vor, dass der Compiler nicht feststellen kann, dass EntityTag die ITaggable-Schnittstelle hat. Zusammenfassend suche ich immer noch nach einer vernünftigen Lösung ... –

+0

Danke, Craig - das ist die Art von eleganter Casting-Lösung, nach der ich gesucht habe, da der Compiler nicht automatisch für mich komponiert. Das hat funktioniert. Wenn Sie Ihren Kommentar in eine Antwort konvertieren, akzeptiere ich das als Lösung. –

1

Ihre EntityTag Klasse IQueryable ist aber der Compiler nicht weiß, dass die Liste der Tags ist eigentlich eine Liste von EntityTag Objekten, sie weiß nur, dass es eine Liste von Objekten, die Umsetzung ITaggable, die wahrscheinlich isn 't IQueryable.

2

C# 4.0 wird es unterstützen. Suche nach „Kovarianz und Kontra in C# 4“