C# 要转换IQueryable的表达式<;t>;整数列表<;选择列表项>;

C# 要转换IQueryable的表达式<;t>;整数列表<;选择列表项>;,c#,linq,lambda,linq-to-entities,expression-trees,C#,Linq,Lambda,Linq To Entities,Expression Trees,我想创建一个存储库方法,如下所示: public List<SelectListItem> AllAsSelectListItems( Expression<Func<T, string>> valueProperty, Expression<Func<T, string>> textProperty, string selectedValue = "") { // what goes here? I

我想创建一个存储库方法,如下所示:

public List<SelectListItem> AllAsSelectListItems(
    Expression<Func<T, string>> valueProperty, 
    Expression<Func<T, string>> textProperty, 
    string selectedValue = "")
{
    // what goes here? I am having serious trouble with this bit!
}
我在使用泛型
AllAsSelectListItems()
方法时遇到问题

您可以在下面的代码中看到我迄今为止的尝试。但这并不理想

我使用了硬编码字符串,用
T
属性填充
SelectListItem
属性。我认为表达式树是解决方案,但我正在努力正确地编码它

另外,分配
ID
属性会破坏它,因为它是
int
而不是
字符串

最后,我还在努力将
selectedValue
参数与
SelectListItem.Value
属性进行比较


个人类别

public class Person
{
    public int ID {get;set;}
    public string Name {get;set;}
}
控制器

public class PersonController : Controller 
{
    public IPersonRepository Repository {get;set;}

    public PersonController(IPersonRepository repository) 
    {
        Repository = repository;
    }

    public ActionResult SelectPerson(int selectedID)
    {
        string selectedIDAsString = selectedID.ToString();
        var selectListItems = Repository.AllAsSelectListItems(
            m => m.ID,
            m => m.Name,
            selectedIDAsString
        );
        return View(selectListItems);
    }
}
存储库

public class PersonRepository : Repository
{
     // various specialised methods 
}

public class Repository<T> : IRepository<T> where T : DBEntity
{
    private ApplicationDbContext db = null;
    private DbSet<T> table = null;

    public RepositoryBase()
    {
        this.db = new ApplicationDbContext();
        table = db.Set<T>();
    }
    public RepositoryBase(ApplicationDbContext db)
    {
        this.db = db;
        table = db.Set<T>();
    }

    protected virtual IQueryable<T> AllAsQueryable(
        params Expression<Func<T, object>>[] includeExpressions)
    {
        return includeExpressions.Aggregate<Expression<Func<T, object>>, IQueryable<T>>
            (table, (current, expression) => current.Include(expression));
    }

    public List<SelectListItem> AllAsSelectListItems(
        Expression<Func<T, string>> valueProperty, 
        Expression<Func<T, string>> textProperty, 
        string selectedValue = "")
    {
        // temp hard coded values until we learn how to use the expression parameters properly
        string valuePropertyHardCoded = "Name";
        string textPropertyHardCoded = "Name";
        Type currentType = typeof(T);
        var itemParam = Expression.Parameter(currentType, "x");
        var valueMember = Expression.PropertyOrField(itemParam, valuePropertyHardCoded);
        var textMember = Expression.PropertyOrField(itemParam, textPropertyHardCoded);

        var selector = Expression.MemberInit(Expression.New(typeof(SelectListItem)),
            Expression.Bind(typeof(SelectListItem).GetMember("Value").Single(), valueMember),
            Expression.Bind(typeof(SelectListItem).GetMember("Text").Single(), textMember)
        );
        var lambda = Expression.Lambda<Func<T, SelectListItem>>(
            selector, itemParam);

        return AllAsQueryable().Select(lambda.Compile()).ToList();
    }
}
公共类PersonRepository:存储库
{
//各种专门方法
}
公共类存储库:IRepository,其中T:DBEntity
{
私有ApplicationDbContext db=null;
私有DbSet表=null;
公共存储库()
{
this.db=new ApplicationDbContext();
table=db.Set();
}
公共存储库(ApplicationDbContext数据库)
{
这个.db=db;
table=db.Set();
}
受保护的虚拟IQueryable AllAsQueryable(
参数表达式[]includeExpressions)
{
返回includeExpressions.Aggregate
(表,(当前,表达式)=>current.Include(表达式));
}
公共列表所有选择列表项(
表达式valueProperty,
表达式textProperty,
字符串selectedValue=“”)
{
//临时硬编码值,直到我们了解如何正确使用表达式参数
字符串valuePropertyHardCoded=“Name”;
字符串textPropertyHardCoded=“Name”;
类型currentType=类型(T);
var itemParam=表达式参数(currentType,“x”);
var valueMember=Expression.PropertyOrField(itemParam,valuePropertyHardCoded);
var textMember=Expression.PropertyOrField(itemParam,textPropertyHardCoded);
var selector=Expression.MemberInit(Expression.New(typeof(SelectListItem)),
Expression.Bind(typeof(SelectListItem).GetMember(“Value”).Single(),valueMember),
Expression.Bind(typeof(SelectListItem).GetMember(“Text”).Single(),textMember)
);
var lambda=表达式.lambda(
选择器,itemParam);
返回AllAsQueryable().Select(lambda.Compile()).ToList();
}
}

你就快到了。要实现的事情很少:

(A) 将传递的
valueProperty
textProperty
表达式绑定到公共参数。由于假设它们表示属性/字段访问器,因此传递的表达式
Body
应为
MemberExpression
类型,并且可以从
MemberExpression.member
属性中提取实际的成员信息

(B) 使用
表达式生成所选
赋值。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;
}

我有点困惑,AllAsSelectListItemsSpecifyProperties是如何尝试编写AllAsSelectListItems的?或者这是另一种有效的方法,好吗?对不起,这是复制粘贴时的打字错误。谢谢你指出这一点。它应该是
AllAsSelectListItems()
。现在已更新。
string selectedValue=”“
参数的用途是什么?与每个
SelectListItem.Value
进行比较。如果它们相同,我们将
SelectListItem.Selected
标记为
true
。非常感谢!!现在我明白了,而且有了你的解释,这是有道理的,但我自己永远也不会想到这个问题。如果我想将
int
属性作为
valueProperty
参数传递,我该怎么做呢?我试图用
Expression
Expression
创建重载,但我不知道如何编辑绑定部分。@martinhansennox让我想一想。问题是它需要转换成
string
我想是吧?我想是的。我正在尝试各种方法,但我不确定我应该在代码中尝试将转换放在哪里。如果这很痛苦,我可以单独提问。我很高兴它现在能在弦上工作:)
public class PersonRepository : Repository
{
     // various specialised methods 
}

public class Repository<T> : IRepository<T> where T : DBEntity
{
    private ApplicationDbContext db = null;
    private DbSet<T> table = null;

    public RepositoryBase()
    {
        this.db = new ApplicationDbContext();
        table = db.Set<T>();
    }
    public RepositoryBase(ApplicationDbContext db)
    {
        this.db = db;
        table = db.Set<T>();
    }

    protected virtual IQueryable<T> AllAsQueryable(
        params Expression<Func<T, object>>[] includeExpressions)
    {
        return includeExpressions.Aggregate<Expression<Func<T, object>>, IQueryable<T>>
            (table, (current, expression) => current.Include(expression));
    }

    public List<SelectListItem> AllAsSelectListItems(
        Expression<Func<T, string>> valueProperty, 
        Expression<Func<T, string>> textProperty, 
        string selectedValue = "")
    {
        // temp hard coded values until we learn how to use the expression parameters properly
        string valuePropertyHardCoded = "Name";
        string textPropertyHardCoded = "Name";
        Type currentType = typeof(T);
        var itemParam = Expression.Parameter(currentType, "x");
        var valueMember = Expression.PropertyOrField(itemParam, valuePropertyHardCoded);
        var textMember = Expression.PropertyOrField(itemParam, textPropertyHardCoded);

        var selector = Expression.MemberInit(Expression.New(typeof(SelectListItem)),
            Expression.Bind(typeof(SelectListItem).GetMember("Value").Single(), valueMember),
            Expression.Bind(typeof(SelectListItem).GetMember("Text").Single(), textMember)
        );
        var lambda = Expression.Lambda<Func<T, SelectListItem>>(
            selector, itemParam);

        return AllAsQueryable().Select(lambda.Compile()).ToList();
    }
}
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;
}
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;
}