你快到了。要实现的事情很少:
(A) 绑定传递的
valueProperty
和
textProperty
表达式转换为公共参数。由于假设它们表示属性/字段访问器,因此传递的表达式
Body
应为类型
MemberExpression
并且可以从中提取实际成员信息
MemberExpression.Member
所有物
(B) 生成
Selected
使用赋值
Expression.Equal
把它们放在一起,看起来会是这样的
public List<SelectListItem> AllAsSelectListItems(
Expression<Func<T, string>> valueProperty,
Expression<Func<T, string>> textProperty,
string selectedValue = "")
{
if (valueProperty == null) throw new ArgumentNullException("valueProperty");
if (textProperty == null) throw new ArgumentNullException("textProperty");
if (!(valueProperty.Body is MemberExpression)) throw new ArgumentException("Must be a field or property.", "valueProperty");
if (!(textProperty.Body is MemberExpression)) throw new ArgumentException("Must be a field or property.", "textProperty");
var item = Expression.Parameter(typeof(T), "x");
var valueMember = Expression.MakeMemberAccess(item, ((MemberExpression)valueProperty.Body).Member);
var textMember = Expression.MakeMemberAccess(item, ((MemberExpression)textProperty.Body).Member);
var targetType = typeof(SelectListItem);
var bindings = new List<MemberBinding>
{
Expression.Bind(targetType.GetProperty("Value"), valueMember),
Expression.Bind(targetType.GetProperty("Text"), textMember)
};
if (!string.IsNullOrEmpty(selectedValue))
bindings.Add(Expression.Bind(targetType.GetProperty("Selected"), Expression.Equal(valueMember, Expression.Constant(selectedValue))));
var selector = Expression.Lambda<Func<T, SelectListItem>>(
Expression.MemberInit(Expression.New(targetType), bindings), item);
var query = AllAsQueryable().Select(selector);
var result = query.ToList();
return result;
}
更新:
不幸地
SelectListItem.Value
属于类型
string
,并且大多数时候源属性(通常是某种Id)不是
一串
。所以让我们重命名
value属性
到
valueSelector
允许传递类似
x => x.Id.ToString()
虽然我们无法轻松地重新绑定传递的表达式,但我们可以轻松地使用它,而不是创建新的参数,只需重用该表达式的参数即可。
修改后的方法如下
public List<SelectListItem> AllAsSelectListItems(
Expression<Func<T, string>> valueSelector,
Expression<Func<T, string>> textProperty,
string selectedValue = "")
{
if (valueSelector == null) throw new ArgumentNullException("valueSelector");
if (textProperty == null) throw new ArgumentNullException("textProperty");
if (!(textProperty.Body is MemberExpression)) throw new ArgumentException("Must be a field or property.", "textProperty");
var item = valueSelector.Parameters[0];
var itemValue = valueSelector.Body;
var itemText = Expression.MakeMemberAccess(item, ((MemberExpression)textProperty.Body).Member);
var targetType = typeof(SelectListItem);
var bindings = new List<MemberBinding>
{
Expression.Bind(targetType.GetProperty("Value"), itemValue),
Expression.Bind(targetType.GetProperty("Text"), itemText)
};
if (!string.IsNullOrEmpty(selectedValue))
bindings.Add(Expression.Bind(targetType.GetProperty("Selected"), Expression.Equal(itemValue, Expression.Constant(selectedValue))));
var selector = Expression.Lambda<Func<T, SelectListItem>>(Expression.MemberInit(Expression.New(targetType), bindings), item);
var query = AllAsQueryable().Select(selector);
var result = query.ToList();
return result;
}