C# 转换表达式<;Func<;T、 对象>&燃气轮机;表达<;Func<;对象>&燃气轮机;
如何将:C# 转换表达式<;Func<;T、 对象>&燃气轮机;表达<;Func<;对象>&燃气轮机;,c#,linq,nhibernate,linq-expressions,C#,Linq,Nhibernate,Linq Expressions,如何将:表达式转换为表达式 例如: public class Entity { public virtual long Id { get; set; } } 来源: Expression<Func<Entity, object>> origin = x => x.Id; expressionorigin=x=>x.Id; 目的地: Entity alias = null; Expression<Func<object>
表达式
转换为表达式
例如:
public class Entity
{
public virtual long Id { get; set; }
}
来源:
Expression<Func<Entity, object>> origin = x => x.Id;
expressionorigin=x=>x.Id;
目的地:
Entity alias = null;
Expression<Func<object>> destination = () => alias.Id;
实体别名=null;
表达式目标=()=>alias.Id;
原因:
实际上,我正在尝试为Nhibernate创建一个自定义的可缓存ResultTransformer。有一个方法public QueryOverProjectionBuilder with alias(表达式别名)
但是在我的类中,对于每个特定的实体,我想使用更具体的选择器,比如表达式您有两个选项:
按照Luaan的建议调用表达式
将参数替换为所需的值(常量或其他表达式)
选项1与表达式一样简单。Invoke
,但可能与LINQ等库不兼容。选项2最好使用expression visitor完成:
private class ExchangeParametersVisitor : ExpressionVisitor
{
public ParameterExpression Parameter { get; set; }
public Expression Value { get; set; }
protected override Expression VisitParameter(ParameterExpression node)
{
if (node == Parameter)
{
return Value;
}
return node;
}
}
您需要做的是将访问者应用于lambda表达式的主体,并使用它创建一个新的lambda表达式,该表达式与以前一样包含除替换的参数外的所有参数。您有两个选项:
按照Luaan的建议调用表达式
将参数替换为所需的值(常量或其他表达式)
选项1与表达式一样简单。Invoke
,但可能与LINQ等库不兼容。选项2最好使用expression visitor完成:
private class ExchangeParametersVisitor : ExpressionVisitor
{
public ParameterExpression Parameter { get; set; }
public Expression Value { get; set; }
protected override Expression VisitParameter(ParameterExpression node)
{
if (node == Parameter)
{
return Value;
}
return node;
}
}
您需要做的是将访问者应用于lambda表达式的主体,并使用它创建一个新的lambda表达式,该表达式与以前一样包含除替换的参数外的所有参数。这就是表达式的作用。Invoke
的作用
创建一个新的lambda表达式,并对原始表达式使用expression.Invoke
,以组合这两个表达式
样本:
Expression<Func<string, int>> inner = x => int.Parse(x);
var outer = Expression.Lambda<Func<int>>
(Expression.Invoke(inner, Expression.Constant("123")));
outer.Compile()().Dump(); // 123
expressioninner=x=>int.Parse(x);
var outer=Expression.Lambda
(Expression.Invoke(内部,Expression.Constant(“123”));
outer.Compile()().Dump();//123
遗憾的是,一些表达式解析器不能正确地处理调用——他们假定这是一个方法调用,并拒绝它。在这种情况下,需要内联表达式。这意味着访问整个内部表达式,并在更好的情况下用变量替换参数expression
s,或者如果解析器也不支持,则在所有位置内联参数。这就是expression.Invoke
的目的
创建一个新的lambda表达式,并对原始表达式使用expression.Invoke
,以组合这两个表达式
样本:
Expression<Func<string, int>> inner = x => int.Parse(x);
var outer = Expression.Lambda<Func<int>>
(Expression.Invoke(inner, Expression.Constant("123")));
outer.Compile()().Dump(); // 123
expressioninner=x=>int.Parse(x);
var outer=Expression.Lambda
(Expression.Invoke(内部,Expression.Constant(“123”));
outer.Compile()().Dump();//123
遗憾的是,一些表达式解析器不能正确地处理调用——他们假定这是一个方法调用,并拒绝它。在这种情况下,需要内联表达式。这意味着访问整个内部表达式,并在更好的情况下用变量替换ParameterExpression
s,或者如果解析器也不支持,则在所有位置内联参数。这个问题毫无意义,一个导出实体的方法应该如何替换为一个不支持的方法?我看不出有任何理由依赖外部范围来摆脱methods参数。听起来你实际上是在试图解决一些不同的问题。那么,你真正的问题是什么?@HimBromBeere我想他想“咖喱”函数——在这个示例中,通过使用闭包。这个问题毫无意义,一个导出实体的方法应该如何替换为一个不导出实体的方法?我看不出有任何理由依赖外部范围来摆脱methods参数。听起来你实际上是在试图解决一些不同的问题。那么,你的实际问题是什么?@HimBromBeere我想他想“curry”函数——在这个示例中,使用闭包。替换参数的一个很好的例子:)尽管我必须注意,你需要确保Value
没有副作用——否则替换参数表达式会带来麻烦。使用变量会更好,但我担心拒绝Invoke
的系统也不支持变量:)@Luaan Yes。由于C#编译器不支持在表达式中使用变量,因此我认为表达式解析器接受变量的可能性甚至比调用表达式的可能性更大。遗憾的是,C#编译器根本不支持包含变量的块式表达式。大多数人在设计他们的库时不会想到F#这样的语言。公平地说,翻译这样的东西并不总是容易的,但例如,EF确实支持let
,可以以类似的方式使用。例如表达式inner=x=>(从x中的a让b=a-'0'选择b)
,它转换为两个“嵌套”Select
s。替换参数的一个很好的例子:)尽管我必须注意,您需要确保Value
没有副作用-否则替换参数表达式将导致麻烦。使用变量会更好,但我担心拒绝Invoke
的系统也不支持变量:)@Luaan Yes。由于C#编译器不支持在表达式中使用变量,因此我认为表达式解析器接受变量的可能性甚至比调用表达式的可能性更大。遗憾的是,C#编译器根本不支持包含变量的块式表达式。大多数人在设计他们的库时不会想到F#这样的语言。公平地说,翻译这样的东西并不总是容易的,但例如EF确实支持let
,可以使用它