使用泛型类型在扩展中忽略c#约束

时间:2016-10-07 08:56:17

标签: c# entity-framework linq generics

public interface ICardEntity { ... }

public class Card : ICardEntity { ... }

public static class MyExtensions
{
    public static List<T> ToList<T>(this IQueryable<T> query) where T : ICardEntity
    { ... }
}

// DbContext
public class ApplicationDbContext : DbContext
{
      public DbSet<Card> Cards { get; set; }
}

.....

var list = dbContext.Cards
     .ToList(); // -- OK, my extension is called
var list2 = dbContext.Cards
     .GroupBy(t => new { Type = t.Type})
     .ToList(); // -- Compile error. Why not System.Linq.Enumerable.ToList() is called?

我希望仅为IQueryable调用我的ToList&lt; ICardEntity&gt;,但不适用于IGrouping&lt;&lt;匿名类型:短H&gt;,卡&gt;。为什么约束&#34;其中T:ICardEntity&#34;不工作?

错误讯息:

  

类型&#39; System.Linq.IGrouping&lt;&lt;匿名类型:短H>,   Nucleo.Tests.Models.Card&GT;&#39;不能用作类型参数&#39; T&#39;在里面   泛型类型或方法&#39; MyExtensions.ToList(IQueryable)&#39;。那里   没有隐式引用转换   &#39;&System.Linq.IGrouping LT ;,   Nucleo.Tests.Models.Card&GT;&#39;到&#39; ICardEntity&#39;。

1 个答案:

答案 0 :(得分:3)

在C#中,通用约束没有超载。您可以重载参数计数和参数类型,但不能重复返回值,通用约束等等。这就是全部。

在重载解析期间,编译器只需要使用ToList(),因为方法的名称以及参数的数量和类型匹配。它之后会验证通用约束,但此时它已经是错误,而不是过载分辨率候选丢失。我不知道如何以更易读的方式表达它。我希望你明白。

经过深思熟虑后 -

如果您习惯使用C ++及其模板,那么它不是C ++,并且没有SFINAE可以让它按照您的想法运行。

所有&#39;重载决议&#39;和&#39;方法匹配/查找/等&#39;必须遵循CLS / CLR的规则,所有语言的整个平台,如VB,C#,F3等.CLS / CLR定义了如何查找方法,如何解决重载候选等等。而且,遗憾的是,重载超出泛型类型参数约束,它不包含在规范中。 IIRC将其添加到规范中会在整个平台上产生几个问题(IIRC,类型和方法解析性能),因此没有添加..但这是我记得的。重要的是,它不在语言和运行时平台规范中。