尝试使用 Expression<Func<..>> 从方法调用 Any() 时出现类型错误
Type error trying to call Any() using Expression<Func<..>> from method
我正在创建一个从我的 EF 实体到我的 BLL 实体的可重用映射表达式:
private Expression<Func<Person, bool>> GetNameFilter(string name)
{
return person => person.Profile.UserName == name;
}
internal Expression<Func<Ef.Perk, Bll.Perk>> MapPerkPerk(string name)
{
return perk => new Bll.Perk
{
Id = perk.PerkId,
Name = perk.PerkName,
Description = perk.PerkDescription,
//Compilation Error
Owned = perk.Players.Any(GetNameFilter(name))
};
}
而且我在注意到的行上遇到编译错误。错误内容为:
ICollection does not contain a definition for 'Any' and the best extension method overload 'Queryable.Any(IQueryable, Expression>)' requires a receiver of type 'IQueryable'
但是当我直接将这个表达式推入时不会发生这种情况:
internal Expression<Func<Ef.Perk, Bll.Perk>> MapPerkPerk(string name)
{
return perk => new Bll.Perk
{
Id = perk.PerkId,
Name = perk.PerkName,
Description = perk.PerkDescription,
//No Compilation Error
Owned = perk.Players.Any(person => person.Profile.UserName == name)
};
}
为什么会这样?两个表达式的类型相同。
使用下面找到的 LinqExpression 解决方案,我现在在运行时遇到以下错误:
An exception of type 'System.InvalidCastException' occurred in LinqKit.dll but was not handled in user code
Additional information: Unable to cast object of type 'System.Linq.Expressions.InstanceMethodCallExpressionN' to type 'System.Linq.Expressions.LambdaExpression'.
internal FutureQuery<Perk> GetPlayerInfoPerks(string username)
{
return Master
.Perks
.VisiblePerks
.Select(Master.Perks.MapPerkPerk(username))
.Future();
}
这是因为使用了 EntityFramework.Future 库吗?
Why is this happening? The type of both expressions is the same.
两个表达式的类型 不相同 - 它们只是在视觉上看起来相同。以下是有效的:
dbContext.Persons.Any(GetNameFilter(name))
这不是:
perk.Players.Any(GetNameFilter(name))
为什么?因为第一个期望 Expression<Func<...>>
而第二个 - 只是 Func<..>
(IQueryable<T>
和 IEnumerable<T>
方法之间具有相同名称的典型区别)。希望你能看出区别。当您直接键入它时,C# 编译器会施展魔法发出一个或另一个,但当您手动执行时,您应该使用正确的。
问题已由 LinqKit 包和 Invoke
/ Expand
自定义扩展方法(更普遍的是 AsExpandable
)解决。
对于您的具体示例,LinqKit 解决方案可能是这样的:
using LinqKit;
...
internal Expression<Func<Ef.Perk, Bll.Perk>> MapPerkPerk(string name)
{
// LinqKit requires expressions to be in variables
var nameFilter = GetNameFilter(name);
return Linq.Expr((Ef.Perk perk) => new Bll.Perk
{
Id = perk.PerkId,
Name = perk.PerkName,
Description = perk.PerkDescription,
Owned = perk.Players.Any(p => nameFilter.Invoke(p))
}).Expand();
}
我正在创建一个从我的 EF 实体到我的 BLL 实体的可重用映射表达式:
private Expression<Func<Person, bool>> GetNameFilter(string name)
{
return person => person.Profile.UserName == name;
}
internal Expression<Func<Ef.Perk, Bll.Perk>> MapPerkPerk(string name)
{
return perk => new Bll.Perk
{
Id = perk.PerkId,
Name = perk.PerkName,
Description = perk.PerkDescription,
//Compilation Error
Owned = perk.Players.Any(GetNameFilter(name))
};
}
而且我在注意到的行上遇到编译错误。错误内容为:
ICollection does not contain a definition for 'Any' and the best extension method overload 'Queryable.Any(IQueryable, Expression>)' requires a receiver of type 'IQueryable'
但是当我直接将这个表达式推入时不会发生这种情况:
internal Expression<Func<Ef.Perk, Bll.Perk>> MapPerkPerk(string name)
{
return perk => new Bll.Perk
{
Id = perk.PerkId,
Name = perk.PerkName,
Description = perk.PerkDescription,
//No Compilation Error
Owned = perk.Players.Any(person => person.Profile.UserName == name)
};
}
为什么会这样?两个表达式的类型相同。
使用下面找到的 LinqExpression 解决方案,我现在在运行时遇到以下错误:
An exception of type 'System.InvalidCastException' occurred in LinqKit.dll but was not handled in user code
Additional information: Unable to cast object of type 'System.Linq.Expressions.InstanceMethodCallExpressionN' to type 'System.Linq.Expressions.LambdaExpression'.
internal FutureQuery<Perk> GetPlayerInfoPerks(string username)
{
return Master
.Perks
.VisiblePerks
.Select(Master.Perks.MapPerkPerk(username))
.Future();
}
这是因为使用了 EntityFramework.Future 库吗?
Why is this happening? The type of both expressions is the same.
两个表达式的类型 不相同 - 它们只是在视觉上看起来相同。以下是有效的:
dbContext.Persons.Any(GetNameFilter(name))
这不是:
perk.Players.Any(GetNameFilter(name))
为什么?因为第一个期望 Expression<Func<...>>
而第二个 - 只是 Func<..>
(IQueryable<T>
和 IEnumerable<T>
方法之间具有相同名称的典型区别)。希望你能看出区别。当您直接键入它时,C# 编译器会施展魔法发出一个或另一个,但当您手动执行时,您应该使用正确的。
问题已由 LinqKit 包和 Invoke
/ Expand
自定义扩展方法(更普遍的是 AsExpandable
)解决。
对于您的具体示例,LinqKit 解决方案可能是这样的:
using LinqKit;
...
internal Expression<Func<Ef.Perk, Bll.Perk>> MapPerkPerk(string name)
{
// LinqKit requires expressions to be in variables
var nameFilter = GetNameFilter(name);
return Linq.Expr((Ef.Perk perk) => new Bll.Perk
{
Id = perk.PerkId,
Name = perk.PerkName,
Description = perk.PerkDescription,
Owned = perk.Players.Any(p => nameFilter.Invoke(p))
}).Expand();
}