- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
getvalueexpre-6ren">
我是表达式的新手,我想知道如何以任何方式转换我的表达式
假设在这个例子中我的 TModel 是 Customer 类型,并像这样将它分配到某个地方:
Expression<Func<TModel, string>> getvalueexpression = customer =>customer.Name
类似于
Expression<Action<TModel,string>> setvalueexpression = [PSEUDOCODE] getvalueexpression = input
Action<TModel,string> Setter = setvalueexpression.Compile();
Setter(mycustomer,value);
简而言之,我想以某种方式构建和编译一个表达式,将我的 getter 表达式指定的客户名称设置为特定值。
最佳答案
修改后的版本。这个类可能比你能在周围找到的许多其他类更好 :-) 这是因为这个版本支持直接属性(p => p.B
)(和其他人一样 :-))、嵌套属性(p => p.B.C.D
),字段(“终端”和“中间”,所以在 p => p.B.C.D
中 B
和 D
可以是字段)和类型的“内部”转换(因此 p => ((BType)p.B).C.D
和 p => (p.B as BType)。 C.D)
。唯一不支持的是“终端”元素的转换(因此没有 p => (object)p.B
)。
生成器中有两个“代码路径”:简单表达式 (p => p.B
) 和“嵌套”表达式。 .NET 4.0 有代码变体(具有 Expression.Assign
表达式类型)。从我的一些基准测试中,最快的委托(delegate)是:“简单”Delegate.CreateDelegate
属性,Expression.Assign
字段和“简单”FieldSetter
对于字段(这比字段的 Expression.Assign
慢一点)。所以在 .NET 4.0 下你应该去掉所有标记为 3.5 的代码。
部分代码不是我的。初始(简单)版本基于 Fluent NHibernate 代码(但它仅支持直接属性),其他一些部分基于 How do I set a field value in an C# Expression tree? 中的代码和 Assignment in .NET 3.5 expression trees .
public static class FluentTools
{
public static Action<T, TValue> GetterToSetter<T, TValue>(Expression<Func<T, TValue>> getter)
{
ParameterExpression parameter;
Expression instance;
MemberExpression propertyOrField;
GetMemberExpression(getter, out parameter, out instance, out propertyOrField);
// Very simple case: p => p.Property or p => p.Field
if (parameter == instance)
{
if (propertyOrField.Member.MemberType == MemberTypes.Property)
{
// This is FASTER than Expression trees! (5x on my benchmarks) but works only on properties
PropertyInfo property = propertyOrField.Member as PropertyInfo;
MethodInfo setter = property.GetSetMethod();
var action = (Action<T, TValue>)Delegate.CreateDelegate(typeof(Action<T, TValue>), setter);
return action;
}
#region .NET 3.5
else // if (propertyOrField.Member.MemberType == MemberTypes.Field)
{
// 1.2x slower than 4.0 method, 5x faster than 3.5 method
FieldInfo field = propertyOrField.Member as FieldInfo;
var action = FieldSetter<T, TValue>(field);
return action;
}
#endregion
}
ParameterExpression value = Expression.Parameter(typeof(TValue), "val");
Expression expr = null;
#region .NET 3.5
if (propertyOrField.Member.MemberType == MemberTypes.Property)
{
PropertyInfo property = propertyOrField.Member as PropertyInfo;
MethodInfo setter = property.GetSetMethod();
expr = Expression.Call(instance, setter, value);
}
else // if (propertyOrField.Member.MemberType == MemberTypes.Field)
{
expr = FieldSetter(propertyOrField, value);
}
#endregion
//#region .NET 4.0
//// For field access it's 5x faster than the 3.5 method and 1.2x than "simple" method. For property access nearly same speed (1.1x faster).
//expr = Expression.Assign(propertyOrField, value);
//#endregion
return Expression.Lambda<Action<T, TValue>>(expr, parameter, value).Compile();
}
private static void GetMemberExpression<T, U>(Expression<Func<T, U>> expression, out ParameterExpression parameter, out Expression instance, out MemberExpression propertyOrField)
{
Expression current = expression.Body;
while (current.NodeType == ExpressionType.Convert || current.NodeType == ExpressionType.TypeAs)
{
current = (current as UnaryExpression).Operand;
}
if (current.NodeType != ExpressionType.MemberAccess)
{
throw new ArgumentException();
}
propertyOrField = current as MemberExpression;
current = propertyOrField.Expression;
instance = current;
while (current.NodeType != ExpressionType.Parameter)
{
if (current.NodeType == ExpressionType.Convert || current.NodeType == ExpressionType.TypeAs)
{
current = (current as UnaryExpression).Operand;
}
else if (current.NodeType == ExpressionType.MemberAccess)
{
current = (current as MemberExpression).Expression;
}
else
{
throw new ArgumentException();
}
}
parameter = current as ParameterExpression;
}
#region .NET 3.5
// Based on https://stackoverflow.com/questions/321650/how-do-i-set-a-field-value-in-an-c-expression-tree/321686#321686
private static Action<T, TValue> FieldSetter<T, TValue>(FieldInfo field)
{
DynamicMethod m = new DynamicMethod("setter", typeof(void), new Type[] { typeof(T), typeof(TValue) }, typeof(FluentTools));
ILGenerator cg = m.GetILGenerator();
// arg0.<field> = arg1
cg.Emit(OpCodes.Ldarg_0);
cg.Emit(OpCodes.Ldarg_1);
cg.Emit(OpCodes.Stfld, field);
cg.Emit(OpCodes.Ret);
return (Action<T, TValue>)m.CreateDelegate(typeof(Action<T, TValue>));
}
// Based on https://stackoverflow.com/questions/208969/assignment-in-net-3-5-expression-trees/3972359#3972359
private static Expression FieldSetter(Expression left, Expression right)
{
return
Expression.Call(
null,
typeof(FluentTools)
.GetMethod("AssignTo", BindingFlags.NonPublic | BindingFlags.Static)
.MakeGenericMethod(left.Type),
left,
right);
}
private static void AssignTo<T>(ref T left, T right) // note the 'ref', which is
{ // important when assigning
left = right; // to value types!
}
#endregion
}
关于c# - Expression<Func<TModel,string>> 到 Expression<Action<TModel>> "Getter"到 "Setter",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7723744/
以下代码产生错误: public static MvcHtmlString EditControlFor(this HtmlHelper htmlHelper, Expression> exp
ASP.NET MVC 中的方法需要表达式 Expression> (在屏幕上显示一个复选框 HTML 控件),但我的成员是 Boolean? . 在我们的案例中,对于这种特定情况,null与fals
我是表达式的新手,我想知道如何以任何方式转换我的表达式 假设在这个例子中我的 TModel 是 Customer 类型,并像这样将它分配到某个地方: Expression> getvalueexpre
我有一个自定义的 HtmlHelper 扩展,它根据助手输入参数呈现控件。 我现在的情况是,我可以呈现任何控件,但 CheckBox 除外。当 CheckBoxFor 助手接受时,Expression
这个问题已经有答案了: Viewing SSRS Reports in an ASP.net MVC Site (9 个回答) 已关闭10 年前。 我正在使用 rdlc 报告(带有 VS2012 的
我有一个传递IEnumerable的方法。然后,根据TModel的类型,该方法执行以下指令集: public void MyMethod(IEnumerable items) where TM
编辑:感谢 David Ruttka,在查看 Mvc3 的 RTM 版本中的 LabelExtensions.cs 后,我能够弄明白。 对于字段名称:字符串字段 = ExpressionHelper.
是否可以创建Expression>()它可以在不同的 htmlHelpers 中使用(例如在 CheckBoxFor() 中),如果我有一个模型对象 this HtmlHelper htmlHelpe
我正在尝试实现一个强类型母版页并使用此页面作为示例: How to create a strongly typed master page using a base controller in ASP
不允许将 Nullable<> 类型作为 System.Web.Mvc.ViewPage 泛型的 TModel 参数传递的可能原因是什么?这有时会很方便。 在 ASP.NET MVC 源代码中定义了
我的表达不是很好,我想改进它们,所以我想知道是否有人可以为我解释是否可以在类中创建一个属性,该属性可以在实例化过程中被赋予一个值,如下所示: new Column{ ColumnProperty =
评估代表 我有一个表达式,我使用一个参数,我想在下面的 DoSomething 函数中使用它的结果。 public void DoSomething (Expression> func){ } 调用
我想为 ASP.NET 和 Razor 创建一种 WebGrid 2.0。 定义一个 ModelClass (TData),WebGrid 应该自己为表格创建 HTML。 TData 的属性应该通过反
我的 Html 辅助方法如下所示 public static MvcHtmlString Control(this MyHtmlHelper helper, string propertyNa
我尝试在 SO 中搜索答案并偶然发现了类似的问题,但我无法使用它们来解决我的问题,因此请尽量不要将其标记为重复。让我们继续进行真正的交易: 我有一个用于标准化 Entity Framework 数据库
我使用一些被序列化的强类型表达式,以允许我的 UI 代码具有强类型排序和搜索表达式。这些是类型 Expression>并按原样使用:SortOption.Field = (p => p.FirstNa
使用这个问题给出的代码 OrderBy is not translated into SQL when passing a selector function Func f = x => x.Name
//ModelFor(person =>person.Name); public void ModelFor( Expression> expression) { //Result s
我有一个包含 2 个表的 Linq2SQL 上下文,一个用于 Users和一个 Posts .最初我有这个查询: var results = db.Users.Select(m => new User
假设我有一个索引 View 。我传入的模型实际上是模型的集合,所以 Html属性类型为 HtmlHelper> .如果我想调用扩展方法(例如,Display() 或 DisplayFor() 在列表中
我是一名优秀的程序员,十分优秀!