我正在做的事情有点麻烦。我最初创建了一个通用层,它位于我的业务对象和工作正常的数据访问层之间。然后,我最近读到了一种叫做表达式树的东西,它显然更有效,并且已经证明是这样,因为我用表达式交换了 Activator.CreateInstance() 并且以指数方式改进了我的通用层。
我仍在阅读整个领域(表达式),但我遇到了一些我想尝试使其通用的代码。目前,您必须传入一个具体类型,例如字符串、整数、十进制等。我只是为了通用。我尝试了几件事但失败了。我想要通用的一点是 Action,我不想传入一个字符串我希望能够通用地传入属性的类型,即 typeof(T).GetProperty("Forename").PropertyType 强>。这可能吗?正在考虑做一个有点 foo bar 的 switch 语句。
提前致谢,Onam。
public class TTT<T> where T : new()
{
public void Do(object t)
{
MethodInfo info = typeof(T).GetProperty("Forename").GetSetMethod();
ParameterExpression param = Expression.Parameter(typeof(string), "val");
MethodCallExpression call = Expression.Call(Expression.Constant(t), info,
new ParameterExpression[] { param });
Action<string> action = Expression.Lambda<Action<string>>(call, param).Compile();
action("hi");
}
}
最佳答案
首先,请注意,这不是执行此操作的好方法;如果您正在构建 Expression
,则没有性能优势每次调用,然后是 Compile()
-ing 它,然后调用它。反射会更快。如果您需要性能,请查看诸如 "FastMember" 之类的库,这将是:
var accessor = TypeAccessor.Create(typeof(T));
accessor[target, "Forename"] = value;
(通过元编程和自动缓存进行了全面优化)
如果你希望类型是动态的,那么有两种选择:
- 使用
Expression.GetActionType
输入并使用DynamicInvoke
- 真的表现不佳(提示:不要这样做) - 输入
Action<object>
并在表达式中进行转换(很好)
所以像这样:
using System;
using System.Linq.Expressions;
using System.Reflection;
class Foo
{
public string Forename {get;set;}
}
class Test<T>
{
public void Do(object target, object value)
{
var obj = Expression.Constant(target, typeof(T));
var member = Expression.PropertyOrField(obj, "Forename");
var param = Expression.Parameter(typeof(object));
Type type;
switch(member.Member.MemberType)
{
case MemberTypes.Field:
type = ((FieldInfo)member.Member).FieldType; break;
case MemberTypes.Property:
type = ((PropertyInfo)member.Member).PropertyType; break;
default:
throw new NotSupportedException(member.Member.MemberType.ToString());
}
var body = Expression.Assign(member, Expression.Convert(param, type));
var lambda = Expression.Lambda<Action<object>>(body, param);
lambda.Compile()(value);
}
}
static class Program
{
static void Main()
{
var obj = new Foo();
new Test<Foo>().Do(obj, "abc");
Console.WriteLine(obj.Forename);
}
}
关于c# - 使用 Action<T> 的表达式树可能吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13414068/