代码之家  ›  专栏  ›  技术社区  ›  Zachary Scott

C list<string>to lambda expression with starter example:重构以处理列表

  •  -1
  • Zachary Scott  · 技术社区  · 14 年前

    我有这个:

    List<string> fields;
    
    fields[0] = "firstFieldName";
    fields[1] = "secondFieldName";
    ...
    fields[n] = "nthFieldName";
    

    我想要这个:

    var selector = p => new {p.firstField, p.secondField, ..., p.nthFieldName}
    
    // selector is of type Expression<Func<Entity, object>>
    

    GoofBallLogic this code 那是西姆莉亚,最后 p => p.column

    // Entity is an object in a diagram from Entity Framework 4
    var p = Expression.Parameter(typeof(Entity, "p");
    
    var selector = Expression.Lambda<Func<Entity, string>(
        Expression.Property(p, columnToGroupBy), p );
    

    编辑:我想要完成的

    我有一个“通用”存储库:

    public class Repository<E, C> : IRepository<E,C>
    {
        private C _dc {get;set;} // ObjectContext (Entity Framework 4)
        private string _entityName {get;set;}
        public string entityKeyName {get;private set;}
        public List<string> entityKeys {get;private set;}
        public Expression<Func<E, object>> entityKey {get;private set;}
        private EntityContainer _containerName {get;set;}
    
        public Repository(C myDC)
        {   _dc = myDC; // TODO: check for null
    
            // Name of "this" ObjectContext
            _containerName = _dc.MetadataWorkspace.GetEntityContainer(
                _dc.DefaultContainerName, DataSpace.CSpace);
    
            // Name of "this" Entity
            _entityName = _containerName.BaseEntitySets
                .Where(p => p.ElementType.Name == typeof (E).Name)
                .Select( p => p.Name).FirstOrDefault();
    
            // String list of the keys
            entityKeys = _containerName
                .BaseEntitySets.First(meta => meta.ElementType.Name == 
                    typeof(E).Name)
                .ElementType.KeyMembers.Select(k => k.Name).ToList();
    
            // Thanks Jon Skeet for this cool comma sep list formula
            entityKeyName = string.Join(",", entityKeys.ToArray() );  
    
            entityKey = Expression.Lambda<Func<E, object>> ... 
    

    如何将EntityKey设置为可在中使用的对象 由于LINQ to Entities需要 在执行.skip().take()之前对集合排序

    编辑:

    令人惊讶的是,orderby可以接受:

    p => "field1,field2,field3"
    

    它允许我的代码执行,但实际上不按字段值排序。我想这是TDD的第一步:使用文字。

    3 回复  |  直到 14 年前
        1
  •  2
  •   Doggett    14 年前

    我发现这是一个有趣的问题,花了一些时间来解决它,并找到了一个相对简单的方法。

    无论如何,这里有一个关于如何进行单个字段排序的示例(我将使用第一个字段),如果您想对更多的字段进行排序,您还必须为它们创建表达式并使用。然后在常规orderby(xxx)之后使用。

        // Create a parameter which passes the object
        ParameterExpression param = Expression.Parameter(typeof(E), "a");
    
        // Create body of lambda expression
        Expression body = Expression.PropertyOrField(param, fieldname);
    
        // Create lambda function
        Expression<Func<E, string>> exp = Expression.Lambda<Func<E, string>>(body, param);
    
        // Compile it so we can use it
        Func<E, string> orderFunc = exp.Compile();
    

    现在您可以执行orderby(orderfunc),它将根据fieldname中命名的属性对列表进行排序。唯一的缺点是它只适用于字符串字段(表达式的返回值)。可能也能解决这个问题。

    固定以使用任何IComparable类型:

            // Create a parameter which passes the field
            ParameterExpression param = Expression.Parameter(typeof(E), "a");
    
            // Create body of lambda expression
            Expression body = Expression.TypeAs(Expression.PropertyOrField(param, fieldname), typeof(IComparable));
    
            // Create lambda function
            Expression<Func<E, IComparable>> exp = Expression.Lambda<Func<E, IComparable>>(body, param);
    
            // Compile it so we can use it
            Func<E, IComparable> orderFunc = exp.Compile();
    
        2
  •  1
  •   Timwi    14 年前

    您无法轻松完成此操作,因为您无法构造 new 运行时不存在的类型的表达式。(您可以在C中使用匿名类型,因为C编译器会为您创建该类型。)

    如果你想这样做 真的很难 方法是,您可以生成一个动态程序集,并实际创建所需的类型。有一个 short example here

    不过,我怀疑有一种更简单的方法。我们需要知道你的目标是什么(你需要这个表达式树做什么),你还没有说明。

        3
  •  0
  •   Timwi    14 年前

    从您编辑的问题中,您似乎只希望能够按多个键排序。只要使用 .OrderBy() 然后 .ThenBy() . 我假设你用的是 IQueryable<E> 在这里:

    IQueryable<E> query = ...;
    IOrderedQueryable<E> ordered = null;
    
    foreach (var key in entityKeys)
    {
        // Code from Doggett to construct the lambda expression for one step
        ParameterExpression param = Expression.Parameter(typeof(E), "a");
        var body = Expression.TypeAs(
            Expression.PropertyOrField(param, key),
            typeof(IComparable));
        var exp = Expression.Lambda<Func<E, IComparable>>(body, param);
    
        if (ordered == null)
            ordered = query.OrderBy(exp);
        else
            ordered = ordered.ThenBy(exp);
    }
    
    var finalQuery = (ordered ?? query).Skip(n).Take(m);