泛型约束和表达式类型求值
本文关键字:类型 表达式 约束 泛型 | 更新日期: 2023-09-27 18:29:19
这是基于我之前的一个问题:EF Code First实现的接口属性
我有这样的东西。
interface IKeywordedEntity
{
ICollection<Keyword> Keywords { get; }
}
class Foo : EntityBase, IKeywordedEntity
{
public virtual ICollection<Keyword> Keywords { get { ... } }
}
EntityBase
的细节并不重要。
最初,我写了这个扩展方法来保持干燥:
public static void WithKeywords<TEntityType>(this EntityTypeConfiguration<TEntityType>
entityTypeConfiguration) where TEntityType : EntityBase, IKeywordedEntity
{
entityTypeConfiguration.HasMany(e => e.Keywords).WithMany();
}
我会这样调用它:
modelBuilder.Entity<Foo>.WithKeywords();
但是,实体框架或C#编译器将lambda中的e
视为IKeywordedEntity
,而不是TEntityType
。这吓坏了实体框架。
知道了这一点,我尝试手动将lambda写为HasMany
的Expression
。我想到了以下内容:
public static void WithKeywords<TEntityType>(this EntityTypeConfiguration<TEntityType>
entityTypeConfiguration) where TEntityType : EntityBase, IKeywordedEntity
{
var rootExpression = Expression.Parameter(typeof (TEntityType));
var expression = Expression.Property(rootExpression, "Keywords");
entityTypeConfiguration.HasMany(Expression.Lambda<Func<TEntityType, ICollection<Keyword>>>(expression, rootExpression)).WithMany();
}
现在IntelliSense向我正确显示了EntityBase
和IKeywordedEntity
的组合,并告诉我e
就是TEntityType
。
我的问题是:为什么lambda中传递/编译的表达式树将e
视为IKeywordedEntity
,而不是TEntityType
?
我不是表达式和Lambdas方面的专家,但我认为这就是正在发生的事情。
当我们只指定一个lambda将其转换为表达式树时,编译器将完成将内容转换为树的工作。在方法体中,编译器可以看到的是IKeyworkedEntity.Keywords
而不是TEntityType.Keywords
,并且它使用显式属性名称,即使用以下
var rootExpression = Expression.Parameter(typeof (IKeyworkedEntity));
var expression = Expression.Property(rootExpression, "Keywords");
这就是我们所看到的问题。现在,如果我们自己构建表达式树,我们知道TEntityType
上有一个属性,并且我们在树中这样说。这导致迁移完成,因为它在类上而不是在接口上看到属性。