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

时间:2022-09-02 12:06:25

I have the following class declaration:

我有以下班级声明:

public class EntityTag : BaseEntity, ITaggable

I have an Html helper method:

我有一个Html助手方法:

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

This is my ASP.NET MVC ascx:

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

When I pass in an IQueryable collection to the ascx, I get this error:

当我向ascx传递一个IQueryable集合时,我得到以下错误:

Compiler Error Message: CS1928: 'System.Web.Mvc.HtmlHelper>' does not contain a definition for 'TagCloud' and the best extension method overload 'EDN.MVC.Helpers.EdnHelpers.TagCloud(System.Web.Mvc.HtmlHelper, System.Linq.IQueryable, int, string)' has some invalid arguments

编译错误信息:CS1928: 'System.Web.Mvc。HtmlHelper>'不包含'TagCloud'的定义和最好的扩展方法重载' edn . mvc . helpers.tagcloud (System.Web.Mvc)。HtmlHelper来。IQueryable, int, string)'有一些无效的参数

If I try to explicitly convert the object collection with this:

如果我试图显式地将对象集合转换为:

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

I get the same error - the values I'm passing in are not liked by the compiler.

我得到了相同的错误——我传递的值不被编译器喜欢。

Shouldn't my EntityTag class automatically be supported as IQueryable? What am I missing? It's got to be something obvious. (I hope.)

难道我的EntityTag类不应该被自动支持为IQueryable吗?我缺少什么?一定是显而易见的。(我希望)。

3 个解决方案

#1


5  

Essentially, you're trying to pass an object of the non-generic type IQueryable to a method that accepts the generic IQueryable<ITaggable>, which the compiler cannot "match", resulting in the CS1928 (since the two types are, in fact, different).

本质上,您试图将非泛型IQueryable类型的对象传递给接受泛型IQueryable 的方法,编译器无法“匹配”该对象,从而导致CS1928(因为这两种类型实际上是不同的)。

In your overload that accepts an IQueryable<object> (which is already doing the necessary conversion to a generic list), you simply need to call the generic version of AsQueryable instead of the non-generic one, as such:

在接受IQueryable的重载中(该重载已经对泛型列表进行了必要的转换),您只需调用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);  
}  

Allow me to add, as well, that IQueryable<T> derives from IQueryable, meaning that not all IQueryable objects are IQueryable<T>, thus making the conversion necessary. If the situation were reversed, i.e. your "real" helper method was defined to handle IQueryable objects, then you certainly would have no problem passing an IQueryable<T> to that method (since all IQueryable<T> objects are, in fact, IQueryable).

请允许我补充一点,IQueryable 源自IQueryable,这意味着并非所有IQueryable对象都是IQueryable ,因此需要进行转换。如果情况相反,比如定义了“real”helper方法来处理IQueryable对象,那么将IQueryable 传递给该方法肯定没问题(因为所有IQueryable 对象实际上都是IQueryable)。

Per Craig Stuntz, a much more elegant solution using LINQ features: <%= Html.TagCloud(Model.Select(t => (ITaggable)t), 6, "entity-tags") %>. You can also use <%= Html.TagCloud(Model.Cast<ITaggable>(), 6, "entity-tags") %> if your queryable provider supports it.

根据Craig Stuntz,使用LINQ特性的更优雅的解决方案:<%= Html.TagCloud(Model)。选择(t => (itagable)t), 6,“实体标签”)%>。如果可查询提供者支持,还可以使用<%= Html.TagCloud(Model.Cast (), 6,“实体标记”)%>。

#2


2  

C# 4.0 will support it. Search for "Covariance and Contravariance in C# 4"

c# 4.0将支持它。搜索“c# 4中的协方差和逆变”

#3


1  

Your EntityTag class is IQueryable, however the compiler doesn't know that your list of tags is actually a list of EntityTag objects, it only knows that it's a list of objects implementing ITaggable, which probably isn't IQueryable.

你的EntityTag类是IQueryable,但是编译器不知道你的标签列表实际上是EntityTag对象的列表,它只知道它是实现ITaggable的对象列表,这可能不是IQueryable。

#1


5  

Essentially, you're trying to pass an object of the non-generic type IQueryable to a method that accepts the generic IQueryable<ITaggable>, which the compiler cannot "match", resulting in the CS1928 (since the two types are, in fact, different).

本质上,您试图将非泛型IQueryable类型的对象传递给接受泛型IQueryable 的方法,编译器无法“匹配”该对象,从而导致CS1928(因为这两种类型实际上是不同的)。

In your overload that accepts an IQueryable<object> (which is already doing the necessary conversion to a generic list), you simply need to call the generic version of AsQueryable instead of the non-generic one, as such:

在接受IQueryable的重载中(该重载已经对泛型列表进行了必要的转换),您只需调用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);  
}  

Allow me to add, as well, that IQueryable<T> derives from IQueryable, meaning that not all IQueryable objects are IQueryable<T>, thus making the conversion necessary. If the situation were reversed, i.e. your "real" helper method was defined to handle IQueryable objects, then you certainly would have no problem passing an IQueryable<T> to that method (since all IQueryable<T> objects are, in fact, IQueryable).

请允许我补充一点,IQueryable 源自IQueryable,这意味着并非所有IQueryable对象都是IQueryable ,因此需要进行转换。如果情况相反,比如定义了“real”helper方法来处理IQueryable对象,那么将IQueryable 传递给该方法肯定没问题(因为所有IQueryable 对象实际上都是IQueryable)。

Per Craig Stuntz, a much more elegant solution using LINQ features: <%= Html.TagCloud(Model.Select(t => (ITaggable)t), 6, "entity-tags") %>. You can also use <%= Html.TagCloud(Model.Cast<ITaggable>(), 6, "entity-tags") %> if your queryable provider supports it.

根据Craig Stuntz,使用LINQ特性的更优雅的解决方案:<%= Html.TagCloud(Model)。选择(t => (itagable)t), 6,“实体标签”)%>。如果可查询提供者支持,还可以使用<%= Html.TagCloud(Model.Cast (), 6,“实体标记”)%>。

#2


2  

C# 4.0 will support it. Search for "Covariance and Contravariance in C# 4"

c# 4.0将支持它。搜索“c# 4中的协方差和逆变”

#3


1  

Your EntityTag class is IQueryable, however the compiler doesn't know that your list of tags is actually a list of EntityTag objects, it only knows that it's a list of objects implementing ITaggable, which probably isn't IQueryable.

你的EntityTag类是IQueryable,但是编译器不知道你的标签列表实际上是EntityTag对象的列表,它只知道它是实现ITaggable的对象列表,这可能不是IQueryable。