我试图用contains运算符动态创建一个linq表达式.
在阅读了与此主题相关的几篇帖子后,我提出了以下代码,允许我执行"包含"评估:
internal static Expression<Func<TEntity, bool>> StringContains<TEntity>(string propertyName, string subString)
{
MethodInfo contains = typeof(JsonLinqParser_Paser).GetMethod("Like");
var param = Expression.Parameter(typeof(TEntity));
var body = Expression.Call(contains, Expression.Property(param, propertyName), Expression.Constant(subString, typeof(string)));
var lambda = Expression.Lambda<Func<TEntity, bool>>(body, param);
return lambda;
}
public static bool Like(string a, string b)
{
return a.Contains(b);
}
Run Code Online (Sandbox Code Playgroud)
这就是这样称呼的:
var expression = Expression.Lambda<Func<TEntity, bool>>(StringContains<TEntity>("FIPSCO_STR", _myStringValue), param);
Run Code Online (Sandbox Code Playgroud)
但是,在运行时,我收到如下错误:
类型'System.Func`2 [DAL.BestAvailableFIP,System.Boolean]'的表达式不能用于返回类型'System.Boolean'
其中"DAL.BestAvailableFIP"是"TEntity"类型.
我确信这与我对lambda表达式缺乏了解有关.谁能告诉我我做错了什么?
是否可以在Linq to Entities中使用该Expression.Coalesce方法(http://msdn.microsoft.com/en-us/library/bb302730.aspx)?怎么样?任何可用的例子?
是否可以使用带表达式的枚举来反映枚举值?考虑这个假设的例程:
public enum Fruit
{
Apple,
Pear
}
public void Foo(Fruit fruit)
{
Foo<Fruit>(() => fruit);
}
public void Foo<T>(Expression<Func<T>> expression)
{
//... example: work with Fruit.Pear and reflect on it
}
Run Code Online (Sandbox Code Playgroud)
Bar() 会给我关于枚举的信息,但我想使用实际值.
背景:我一直在添加一些辅助方法来返回类型的CustomAttribute信息,并想知道类似的例程是否可以用于枚举.
我完全知道你可以使用枚举类型来获取CustomAttributes.
更新:
我在MVC中使用类似的概念和辅助扩展:
public class HtmlHelper<TModel> : System.Web.Mvc.HtmlHelper<TModel>
{
public void BeginLabelFor<TProperty>(Expression<Func<TModel, TProperty>> expression)
{
string name = ExpressionHelper.GetExpressionText(expression);
}
}
Run Code Online (Sandbox Code Playgroud)
在此示例中,name将是模型的成员名称.我想用枚举做类似的事情,所以名字将是枚举'成员'.这甚至可能吗?
更新示例:
public enum Fruit
{
[Description("I am a pear")]
Pear
}
public void ARoutine(Fruit fruit)
{
GetEnumDescription(() => fruit); …Run Code Online (Sandbox Code Playgroud) 实际上,有四个相关的问题:
1)为什么可以这样做?
Expression<Func<int, int>> incrementorExpression = (i => i + 1);
Run Code Online (Sandbox Code Playgroud)
但是不能这样做?
LambdaExpression decrementorExpression = (i => i - 1);
Run Code Online (Sandbox Code Playgroud)
在第二种情况下,编译器因此报告:"无法将lambda表达式转换为类型'System.Linq.Expressions.LambdaExpression',因为它不是委托类型"
2)如果是的铸造TDelegate和Expression<TDelegate>申报?我想我记得过去见过它但现在似乎无法找到它.但我无法确定我是否看到了它.
3)当我这样做时:
Expression<Func<int, int>> incrementExpression = (i => ++i);
Run Code Online (Sandbox Code Playgroud)
编译器说:"表达式树可能不包含赋值运算符." 为什么会这样?
4)如果我能做到这一点:
Expression<Func<int, int>> incrementorExpression = (i => i + 1);
Run Code Online (Sandbox Code Playgroud)
那么,为什么我不能做这个?
public Expression<Func<T>> ToExpression<T>(Func<T> func)
{
return func;
}
Run Code Online (Sandbox Code Playgroud) 我有一个生成的 lambda,但是当我想观看它时,它就像一个普通的 lambda,它只是不显示任何内容。当我打电话时,expr.Body.ToString()我得到以下信息:
{var compareA; ... }
Run Code Online (Sandbox Code Playgroud)
但是用于表达式的 DebugView 工作正常:
.Lambda #Lambda1<System.Comparison`1[XLinq.Test.Comparers.CustomComparerTest+Test]>(
XLinq.Test.Comparers.CustomComparerTest+Test $x,
XLinq.Test.Comparers.CustomComparerTest+Test $y) {
.Block(System.Int32 $compareA) {
$compareA = .Call ($x.A).CompareTo($y.A);
.If ($compareA != 0) {
.Return #Label1 { $compareA }
} .Else {
.Block(System.Int32 $compareB) {
$compareB = .Call ($x.B).CompareTo($y.B);
.If ($compareB != 0) {
.Return #Label1 { $compareB }
} .Else {
.Block(System.Int32 $compareC) {
$compareC = .Call ($x.C).CompareTo($y.C);
.If ($compareC != 0) {
.Return #Label1 { $compareC }
} .Else {
.Block(System.Int32 …Run Code Online (Sandbox Code Playgroud) 我有一个函数生成一个表达式来过滤一个表的主键,当传入时Object[],这与Find函数非常相似,只是它没有实现,所以你可以IQueryable在之后传递一个
public static Expression<Func<T, bool>> FilterByPrimaryKeyPredicate<T>(this DbContext dbContext, object[] id)
{
var keyProperties = dbContext.GetPrimaryKeyProperties<T>();
var parameter = Expression.Parameter(typeof(T), "e");
var body = keyProperties
// e => e.{propertyName} == new {id = id[i]}.id
.Select((p, i) => Expression.Equal(
Expression.Property(parameter, p.Name),
Expression.Convert(
Expression.PropertyOrField(Expression.Constant(new { id = id[i] }), "id"),
p.ClrType)))
.Aggregate(Expression.AndAlso);
return Expression.Lambda<Func<T, bool>>(body, parameter);
}
Run Code Online (Sandbox Code Playgroud)
这通过首先获取表的主键,它创建二进制表达式foreach属性,Id以匿名类型包装以利用查询缓存.这工作正常.但是,我想更进一步.
我想保留Expression,所以每次传递一组新的id时我都不必生成它,如何Expression在仍然利用查询缓存的同时存储它?
编辑TL; DR
所以我试图在静态类中使用数组访问来缓存它,但是我遇到了一个错误:
public class PrimaryKeyFilterContainer<T>
{
const string ANON_ID_PROP = "id";
static Expression<Func<T, bool>> _filter; …Run Code Online (Sandbox Code Playgroud) 我有以下内容:
class Base
class Derived : Base
IQueryable<Derived> queryable = ???
Expression<Func<Base, bool>> filter = ???
Run Code Online (Sandbox Code Playgroud)
我想用表达式过滤可查询,然后返回一个IQueryable<Derived>.
但是,Expression是不变的.这意味着queryable.Where(filter)被推断为Where(this IQueryable<Base>, Expression<Func<Base, bool>>),IQueryable<Base>而不是返回IQueryable<Derived>.
C#不允许filter被转换为Expression<Func<Derived, bool>>和的铸造IQueryable<Base>返回通过Where对IQueryable<Derived>在运行时出现故障.
围绕这个最好的方法是什么?
我正在开发一个程序,该程序根据一组输入在运行时计算表达式,然后远程执行这些表达式。这需要动态创建调用不同辅助函数的表达式。
对于静态辅助函数,可以通过使用以下方式获取 MethodInfo 实例来保证编译时安全:
var myMethodInfo = ((Func<int, int>) Helpers.MyStaticHelper.DoSomethingUseful).Method
Run Code Online (Sandbox Code Playgroud)
使用这个,如果Helpers.MyStaticHelper.DoSomethingUseful要更改它的名称或签名,这将导致编译时错误。但是,它似乎仅适用于静态方法。对非静态使用类似的方法给出了 CS0120An object reference is required for the nonstatic field, method, or property 'Helpers.MyDynamicHelper.DoSomethingElse(int, int)'。
可以通过使用类似以下内容来解决此问题:
var myMethodInfo = typeof(Helpers.MyDynamicHelper).GetMethod("DoSomethingElse")
Run Code Online (Sandbox Code Playgroud)
DoSomethingElse但是,如果更改,这将面临运行时异常的风险。我知道在没有实例的情况下不可能调用该方法,但是收集和缓存先决数据需要这些实例,因此在执行表达式之前创建的任何实例都是不正确的。
是否可以在没有实例的情况下获得该方法的编译时安全 MethodInfo?
我试图使用看起来像这样的表达式创建一个可重用的方法:
Expression<Func<Order, bool>> CreateExpression(Expression<Func<Order, int>> parameter, FilterOperator operator, int value)
Run Code Online (Sandbox Code Playgroud)
所以我可以像这样使用它:
IQueryable<Order> orders = db.Orders;
var filtered = orders.Where(CreateExpression(o => o.OrderID, FilterOperator.GreaterThan, 100));
Run Code Online (Sandbox Code Playgroud)
我不知道怎么写这个方法.如何编写一个为我创建此Expression的方法?
我需要能够做这样的事情:
if(operator == FilterOperator.GreaterThan)
return m => m.OrderID > value;
else if(operator == FilterOperator.LessThan)
return m => m.OrderID < value;
Run Code Online (Sandbox Code Playgroud)
但我想使用传入的表达式而不是直接使用OrderID.我怎样才能做到这一点?
c# ×10
linq-expressions ×10
linq ×4
lambda ×3
.net ×2
.net-core ×1
iqueryable ×1
query-cache ×1
reflection ×1
variance ×1