c# - 如何从 lambda 访问属性
问题描述
我想重构这段代码以摆脱依赖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);
但这里有错误:
委托 'Func' 不接受 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);
编辑:编辑答案,因为初始解决方案不适用于值类型,请参阅类型成员的表达式导致不同的表达式(MemberExpression,UnaryExpression)
推荐阅读
- python - DatabaseError: 对 sql 对象执行失败': 要执行的第一个参数必须是字符串或 unicode 查询
- r - 使用 data.table 滚动窗口和自联接
- django - 如何使用带有外键的 django api
- http - 如何查看网页在哪个版本的http上运行?
- javascript - 当 api 需要时间(或仍在处理中)时,Angularjs $http.post 得到“net::ERR_EMPTY_RESPONSE”响应
- git - Return the Number of the Last Merged Pull Request Git
- sql - 如何将带有输入参数的microsoft access查询导入excel
- javascript - 获取 webpack 包中包含的主要库/模块的版本
- powershell - PowerShell gc 缺少括号
- php - LARAVEL:如何使用 SOLID 原则的开闭原则?