c# - 在 LINQ to Entities (EF4.1) 中返回具有类型约束的泛型输入类型

标签 c# linq generics linq-to-entities

我有一个简单的扩展方法,用于按标签过滤 LINQ IQueryable。我将其与 LINQ to Entities 一起使用,接口(interface)为:

public interface ITaggable
{
    ICollection<Tag> Tags { get; } 
}

以下不起作用,返回 IQueryable<ITaggable>而不是 IQueryable<T> :

public static IQueryable<T> WhereTagged<T>(this IQueryable<T> set, string tag) where T:ITaggable
    {
        return set.Where(s=>s.Tags.Any(t=>t.Name.ToLower() == tag.ToLower()));
    }

这会导致 LINQ to Entities 转换异常:

"Unable to cast the type 'ReleaseGateway.Models.Product' to type 'ReleaseGateway.Models.ITaggable'. LINQ to Entities only supports casting Entity Data Model primitive types." (System.NotSupportedException) A System.NotSupportedException was caught: "Unable to cast the type 'Project.Models.Product' to type 'Project.Models.ITaggable'. LINQ to Entities only supports casting Entity Data Model primitive types."

它在没有这样的约束的情况下工作,但我必须在我的应用程序代码中显式声明类型 T:

public static IQueryable<T> WhereTagged<T>(this IQueryable<ITaggable> set, string tag)
{
    return set.Where(s=>s.Tags.Any(t=>t.Name.ToLower() == tag.ToLower())).Cast<T>();
}

问题:为什么类型约束会强制转换返回类型?我可以重写它以利用从扩展方法调用者推断类型吗?

最佳答案

我怀疑问题是由对 s.Tags 的调用引起的.因为sProduct , 但你调用 ITaggable.Tags ,生成的表达式看起来更像:

set.Where(s=>((ITaggable)s).Tags.Any(...))

这只会混淆 Entity Framework 。试试这个:

((IQueryable<ITaggable>)set)
    .Where(s=>s.Tags.Any(t=>t.Name.ToLower() == tag.ToLower()))
    .Cast<T>();

IQueryable是协变接口(interface),这会将集合视为 IQueryable<ITaggable> ,这应该有效,因为您的第二个示例基本上做完全相同的事情。

关于c# - 在 LINQ to Entities (EF4.1) 中返回具有类型约束的泛型输入类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8175134/

相关文章:

Java、泛型、合并、比较

c# - JavaScript 中未定义 URL

c# - 如何在 EF Where() 子句中使用 Predicate<T>?

c# - C# 4 是否以以前的 C# 版本没有的方式优化命名空间?

c# - 通用扩展方法的编译器错误

c++ - 通用类型的 is_base_of

c# - String.Format 基于三级表达式的结果?

c# - 展平 LINQ 集合

c# - Count 和 foreach 产生不同的结果

c# - 用于设置对象属性的 Linq 表达式树是什么?