使用表达式树检索强类型属性名称
本文关键字:属性 强类型 检索 表达式 | 更新日期: 2023-09-27 18:29:44
我希望使用表达式树来获取Domain类型的属性名。这最终将在EF上下文中用于发送脏字段的更新。到目前为止,我有以下内容,我想确认以下内容是一个更不完整的实现,以及是否有更灵活/更高性能的方法来做到这一点:
class Message
{
public int ID
{
get;
set;
}
public string Body
{
get;
set;
}
}
internal static class Program
{
public static string GetPropertyName(Expression<Func<Message,object>> exp)
{
string propName = "";
UnaryExpression ue = exp.Body as UnaryExpression;
if(ue != null)
{
propName = (ue.Operand as MemberExpression).Member.Name;
}
MemberExpression me = exp.Body as MemberExpression;
if(me != null)
{
var constExpression = me.Expression as ConstantExpression;
var field = me.Member as FieldInfo;
if (constExpression != null)
if (field != null)
propName = field.GetValue(constExpression.Value).ToString();
}
ConstantExpression ce = exp.Body as ConstantExpression;
if(ce != null)
{
propName = ce.Value.ToString();
}
MethodCallExpression mc = exp.Body as MethodCallExpression;
if(mc != null)
{
//ParameterExpression param = Expression.Parameter(typeof(Message));
ParameterExpression param = mc.Arguments.OfType<ParameterExpression>().FirstOrDefault();
propName = Expression.Lambda(exp.Body, param).Compile().DynamicInvoke(new Message()).ToString();
}
return propName;
}
private static string SomeMethod(Message m)
{
return "ID";
}
private static Expression<Func<Message,object>>[] GetExpressions()
{
string[] props = new[] { "ID", "Name" };
var expressions =
props.Select(p =>
{
Expression<Func<Message,object>> exp = m => p;
return exp;
}).ToArray();
return expressions;
}
public static void Main(string[] args)
{
string str = "id";
Expression<Func<Message, object>> exp1 = m => str;
Expression<Func<Message, object>> exp2 = m => "id";
Expression<Func<Message, object>> exp3 = m => m.ID;
Expression<Func<Message, object>> exp4 = m => SomeMethod(m);
var expressions = GetExpressions();
string s = GetPropertyName(exp1);
s = GetPropertyName(exp2);
s = GetPropertyName(exp3);
s = GetPropertyName(exp4);
foreach (var exp in expressions)
{
s = GetPropertyName(exp);
}
}
}
这篇SO文章试图做一些类似的事情,但似乎没有涵盖上面的用例。注意:此处不允许使用"nameof"。
我会使用ExpressionVisitor来完成。
class Message
{
public int ID {
get;
set;
}
public string Body {
get;
set;
}
}
internal static class Program
{
private static string SomeMethod(Message m) {
return "ID";
}
private static Expression<Func<Message, object>>[] GetExpressions() {
string[] props = new[] { "ID", "Name" };
var expressions =
props.Select(p => {
Expression<Func<Message, object>> exp = m => p;
return exp;
}).ToArray();
return expressions;
}
public class NameResolverExpressionVisitor : ExpressionVisitor
{
private Expression<Func<Message, object>> exp;
public string Name { get; private set; }
public override Expression Visit(Expression node) {
var casted = node as Expression<Func<Message, object>>;
if (casted != null) {
exp = casted;
}
return base.Visit(node);
}
protected override Expression VisitMember(MemberExpression node) {
var constExpression = node.Expression as ConstantExpression;
var field = node.Member as FieldInfo;
if (constExpression != null && field != null) {
Name = field.GetValue(constExpression.Value).ToString();
}
return base.VisitMember(node);
}
protected override Expression VisitMethodCall(MethodCallExpression node) {
Name = exp.Compile().DynamicInvoke(new Message()).ToString();
return base.VisitMethodCall(node);
}
protected override Expression VisitUnary(UnaryExpression node) {
var memberExpression = node.Operand as MemberExpression;
if (memberExpression != null) {
Name = memberExpression.Member.Name;
}
return base.VisitUnary(node);
}
protected override Expression VisitConstant(ConstantExpression node) {
if (node.Value.GetType().Equals(typeof(string))) {
Name = node.Value.ToString();
}
return base.VisitConstant(node);
}
}
public static void Main(string[] args) {
string str = "id";
Expression<Func<Message, object>> exp1 = m => str;
Expression<Func<Message, object>> exp2 = m => "id";
Expression<Func<Message, object>> exp3 = m => m.ID;
Expression<Func<Message, object>> exp4 = m => SomeMethod(m);
var expressions = GetExpressions();
var visitor = new NameResolverExpressionVisitor();
visitor.Visit(exp1);
Console.WriteLine(visitor.Name);
visitor.Visit(exp2);
Console.WriteLine(visitor.Name);
visitor.Visit(exp3);
Console.WriteLine(visitor.Name);
visitor.Visit(exp4);
Console.WriteLine(visitor.Name);
foreach (var exp in expressions) {
visitor.Visit(exp);
Console.WriteLine(visitor.Name);
}
}
}