2010-01-08 55 views
5

我有以下類聲明:爲什麼c#不支持將接口作爲參數的對象?

public class EntityTag : BaseEntity, ITaggable 

我有一個HTML helper方法:

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

這是我的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") %> 

當我通過一個IQueryable集合到ascx,我得到這個錯誤:

Compil er錯誤消息:CS1928:'System.Web.Mvc.HtmlHelper>'沒有包含'TagCloud'的定義和最佳擴展方法重載'EDN.MVC.Helpers.EdnHelpers.TagCloud(System.Web.Mvc.HtmlHelper, System.Linq.IQueryable,INT,字符串)」有一些無效參數

如果我嘗試顯式轉換對象集合與此:

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

我得到同樣的錯誤 - 我傳遞的價值觀不被編譯器所喜歡。

我的EntityTag類不應該自動支持IQueryable嗎?我錯過了什麼?這肯定是顯而易見的。 (我希望)

+0

ITaggable繼承自IQueryable嗎? – 2010-01-08 01:25:36

+0

你傳遞的模型參數是什麼?我猜這個參數不能轉換爲IQueryable,出於某種原因。 – 2010-01-08 01:26:48

+0

託尼:EntityTag從BaseEntity下降並實現ITaggable – 2010-01-08 18:55:27

回答

5

本質「在C#4協變和逆變」,你要非泛型類型IQueryable的對象傳遞給接受通用IQueryable<ITaggable>的方法,其編譯器無法「匹配」,從而導致在CS1928中(因爲這兩種類型實際上是不同的)。

在你重載接受一個IQueryable<object>(這已經在做必要的轉換,以一個泛型列表),你只需要調用的AsQueryable代替非泛型一個通用版本,例如:

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

請允許我補充,同時,也派生IQueryable<T>IQueryable,這意味着並不是所有的IQueryable對象IQueryable<T>,從而使轉換的必要。如果情況相反,即您的「真實」輔助方法被定義爲處理IQueryable對象,那麼將該方法傳遞給IQueryable<T>(因爲實際上所有IQueryable<T>對象實際上都是IQueryable),您當然不會有任何問題。

Per Craig Stuntz,使用LINQ功能的更優雅的解決方案: <%= Html.TagCloud(Model.Select(t => (ITaggable)t), 6, "entity-tags") %>。如果您的可查詢供應商支持,您也可以使用<%= Html.TagCloud(Model.Cast<ITaggable>(), 6, "entity-tags") %>

+1

這是正確的原因(+1),但我會用一個更簡單的解決方案:'<%= Html.TagCloud(Model.Select(t =>(ITaggable)t ),6,「entity-tags」)%>'。如果您的可查詢提供程序支持它,也可以使用'IEnumerable .Cast()'。 – 2010-01-08 13:14:58

+0

感謝您的回覆。不幸的是,當基於接口的版本也被聲明時,編譯器從不會選擇第二個版本,即使我投入了ascx。儘管如此,編譯器仍然無法確定EntityTag具有ITaggable接口,但它仍然令我感到奇怪。總之,我仍然在尋找一個合理的解決方案... – 2010-01-08 18:53:58

+0

謝謝,克雷格 - 這是我尋找的優雅的鑄造解決方案,因爲編譯器不會自動投給我。這工作。如果您將您的評論轉換爲答案,我會接受它作爲解決方案。 – 2010-01-08 18:58:23

1

EntityTag類是IQueryable,但是編譯器不知道你的標籤列表實際上是EntityTag對象的列表,只知道它的實施ITaggable對象的列表,這可能ISN 't IQueryable

相關問題