【问题标题】:How to access property from lambda如何从 lambda 访问属性
【发布时间】:2019-03-27 14:15:41
【问题描述】:

我想重构这段代码以摆脱对TModel, TValue的依赖

public static string DescriptionFor<TModel, TValue>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
{
    // null checks

    DescriptionAttribute descriptionAttribute = null;
    if (expression.Body is MemberExpression memberExpression)
    {
        descriptionAttribute = memberExpression.Member
            .GetCustomAttributes(typeof(DescriptionAttribute), false)
            .Cast<DescriptionAttribute>()
            .SingleOrDefault();
    }

    return descriptionAttribute?.Description ?? string.Empty;
}

有这样的调用:

@Html.DescriptionFor(x => x.MyModel.MyOtherModel.Property)

类似的事情

public static string DescriptionFor2<T>(Expression<Func<T>> expression)
{
    if (expression == null)
        throw new ArgumentNullException(nameof(expression));

    if (!(expression.Body is MemberExpression memberExpression))
    {
        return string.Empty;
    }

    foreach (var property in typeof(T).GetProperties())
    {
        if (property == ((expression.Body as MemberExpression).Member as PropertyInfo))
        {
            var attr = property
                        .GetCustomAttributes(typeof(DescriptionAttribute), false)
                        .Cast<DescriptionAttribute>()
                        .FirstOrDefault();

            return attr?.Description ?? string.Empty;
        }
    }

    return string.Empty;       
}

这样调用:

@MyHtml.DescriptionFor2<MyOtherModel>(x => x.MyProperty);

但这里有错误:

Delegate 'Func' 不接受 1 个参数

【问题讨论】:

    标签: c# delegates system.reflection


    【解决方案1】:

    你可以这样做:

    void Main()
    {
        Console.WriteLine(MyHtml.DescriptionFor2<Test>((t) => t.StringMember));
        Console.WriteLine(MyHtml.DescriptionFor2<Test>((t) => t.BooleanMember));
        Console.WriteLine(MyHtml.DescriptionFor2<Test>((t) => t.IntegerMember));
    }
    
    public class Test
    {
        [Description("This is a string member")]
        public string StringMember { get; set; }
        [Description("This is a boolean member")]
        public bool BooleanMember { get; set; }
        [Description("This is a integer member")]
        public int IntegerMember { get; set; }
    }
    
    public static class MyHtml
    {
        public static string DescriptionFor2<T>(Expression<Func<T, dynamic>> expression)
        {
            var result = string.Empty;
            var member = GetMemberExpression(expression)?.Member?.Name;
            if (member != null)
            {
                var property = typeof(T).GetProperty(member);
                if (property != null)
                {
                    var attr = property
                                .GetCustomAttributes(typeof(DescriptionAttribute), false)
                                .Cast<DescriptionAttribute>()
                                .FirstOrDefault();
    
                    result = attr?.Description ?? string.Empty;
                }
            }
    
            return result;
        }
    
        private static MemberExpression GetMemberExpression<T>(Expression<Func<T, dynamic>> expression)
        {
            var member = expression.Body as MemberExpression;
            var unary = expression.Body as UnaryExpression;
            return member ?? (unary != null ? unary.Operand as MemberExpression : null);
        }
    }
    
    public class DescriptionAttribute : Attribute
    {
        public string Description { get; set; }
    
        public DescriptionAttribute(string description)
        {
            Description = description;
        }
    }
    

    它涉及获取表达式的主体作为成员并使用其名称来解析对象上的属性。 dynamic 数据类型用于去掉第二个类型参数,但是您也可以显式定义它以更好地捕获编译时错误:

    public static string DescriptionFor2<T, U>(Expression<Func<T, U>> expression)
    

    并调用它:

    MyHtml.DescriptionFor2<Test, string>((t) => t.StringMember);
    MyHtml.DescriptionFor2<Test, bool>((t) => t.BooleanMember);
    MyHtml.DescriptionFor2<Test, int>((t) => t.IntegerMember);
    

    编辑:已编辑答案,因为初始解决方案不适用于值类型,请参阅 Expression for Type members results in different Expressions (MemberExpression, UnaryExpression)

    【讨论】:

    • 我看到您最近的编辑已经完成了一半...我的答案仍然有效,Func 需要输入和输出类型。
    • 我不知道为什么,但对于 string property 它工作正常,但对于 bool 部分 (expression.Body as MemberExpression); 为空 - 使用动态方法
    • 我发现这不适用于值类型,请参阅stackoverflow.com/questions/12975373/… 以获得解决方案。
    猜你喜欢
    • 2011-02-18
    • 2020-09-15
    • 2018-08-11
    • 2016-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-25
    • 2017-07-26
    相关资源
    最近更新 更多