亲爱的反思之神
我想有一个通用的GetValue<TEntity, T>
方法,可以返回以下属性值给定以下User
类:
public class User
{
public int Id { get; set; }
public int ClientId { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string MobileNumber { get; set; }
public bool IsActive { get; set; }
public Client Client { get; set; }
public List<Package> Packages { get; set; }
}
GetValue<TEntity, T>
应该能够做的示例用法:
var firstName = dataCollector.GetValue<User, string>(x => x.FirstName);
var client = dataCollector.GetValue<User, Client>(x => x.Client);
var packages = dataCollector.GetValue<User, List<Package>>(x => x.Packages);
var packageFirst = dataCollector.GetValue<User, Package>(x => x.Packages[0]);
var packageName = dataCollector.GetValue<User, string>(x => x.Packages[0].Name);
var clientName = dataCollector.GetValue<User, string>(x => x.Client.Name);
到目前为止,我有以下方法适用于前3种情况:
public T GetValue<TEntity, T>(Expression<Func<TEntity, T>> propertyExpression) where TEntity : class
{
var response = _responses.FirstOrDefault(p => p.GetType() == typeof(TEntity)) as TEntity;
if (response != null)
{
var expr = (MemberExpression)propertyExpression.Body;
var prop = (PropertyInfo)expr.Member;
return (T)prop.GetValue(response);
}
return default(T);
}
但它不工作的最后三个场景:
var packageFirst = dataCollector.GetValue<User, Package>(x => x.Packages[0]);
抛出:Unable to cast object of type 'System.Linq.Expressions.InstanceMethodCallExpressionN' to type 'System.Linq.Expressions.MemberExpression'.
var packageName = dataCollector.GetValue<User, string>(x => x.Packages[0].Name);
抛出:Object does not match target type.
var clientName = dataCollector.GetValue<User, string>(x => x.Client.Name);
抛出:Object does not match target type.
我需要对方法做什么更改?
我现在将牺牲一个u盘等待你的答案:)
问题就在这里:
if (response != null)
{
var expr = (MemberExpression)propertyExpression.Body;
var prop = (PropertyInfo)expr.Member;
return (T)prop.GetValue(response);
}
如果表达式直接引用属性,则仅有效,否则propertyExpression.Body
将不是MemberExpression
,并且您将得到运行时强制转换错误。不工作的三个不直接引用属性——前两个引用属性顶部的方法(索引器),最后一个引用嵌套属性。
因为你想要的只是表达式的值,所以我认为你可以这样做:
if (response != null)
{
Func<TEntity, T> func = propertyExpression.Compile();
return func(response);
}
如果你打算用表达式做其他事情(比如获取属性的名称),那么你需要决定是否要支持不直接引用属性的表达式,并为此添加处理程序。
您可以通过执行Lambda表达式来实现:
if (response != null)
{
return propertyExpression.Compile().Invoke(response);
}