为什么c#不支持将接口作为参数的对象?

Joh*_*ter 5 .net c# asp.net-mvc

我有以下类声明:

public class EntityTag : BaseEntity, ITaggable
Run Code Online (Sandbox Code Playgroud)

我有一个Html帮助方法:

public static string TagCloud(this HtmlHelper html, IQueryable<ITaggable> taggables, 
  int numberOfStyleVariations, string divId)
Run Code Online (Sandbox Code Playgroud)

这是我的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") %>
Run Code Online (Sandbox Code Playgroud)

当我将IQueryable集合传递给ascx时,我收到此错误:

编译器错误消息:CS1928:'System.Web.Mvc.HtmlHelper>'不包含'TagCloud'的定义和最佳扩展方法重载'EDN.MVC.Helpers.EdnHelpers.TagCloud(System.Web.Mvc.HtmlHelper, System.Linq.IQueryable,int,string)'有一些无效的参数

如果我尝试使用以下方法显式转换对象集合:

    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);
    }
Run Code Online (Sandbox Code Playgroud)

我得到了同样的错误 - 编译器不喜欢我传入的值.

我的EntityTag类不应该自动支持IQueryable吗?我错过了什么?它必须是明显的东西.(我希望.)

Ste*_*veH 5

本质上,您试图将非泛型类型的对象传递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);  
}  
Run Code Online (Sandbox Code Playgroud)

还允许我添加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") %>如果您的可查询提供程序支持它,您也可以使用它.