使用表达式树检索强类型属性名称

本文关键字:属性 强类型 检索 表达式 | 更新日期: 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);
        }
    }
}