c#列表<;字符串>;使用starter创建Lambda表达式示例:重构以处理列表

c#列表<;字符串>;使用starter创建Lambda表达式示例:重构以处理列表,c#,entity-framework-4,lambda,C#,Entity Framework 4,Lambda,我有这个: List<string> fields; fields[0] = "firstFieldName"; fields[1] = "secondFieldName"; ... fields[n] = "nthFieldName"; 编辑:我正在努力实现的目标 我有一个“通用”存储库: public class Repository<E, C> : IRepository<E,C> { private C _dc {get;set;} //

我有这个:

List<string> fields;

fields[0] = "firstFieldName";
fields[1] = "secondFieldName";
...
fields[n] = "nthFieldName";
编辑:我正在努力实现的目标

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

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>> ... 

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

您无法轻松做到这一点,因为您无法为运行时不存在的类型构造新的
表达式。(您可以在C#中使用匿名类型,因为C#编译器会为您创建该类型。)

如果您想以非常困难的方式完成,可以生成动态程序集并实际创建所需的类型。有一个问题


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

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

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

//创建一个传递对象的参数
ParameterExpression param=表达式参数(类型为(E),“a”);
//创建lambda表达式的主体
表达式体=Expression.PropertyOrField(参数,字段名);
//创建lambda函数
表达式exp=表达式Lambda(body,param);
//编译它以便我们可以使用它
Func 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();
//创建一个传递该字段的参数
ParameterExpression param=表达式参数(类型为(E),“a”);
//创建lambda表达式的主体
Expression body=Expression.TypeAs(Expression.PropertyOrField(param,fieldname),typeof(IComparable));
//创建lambda函数
表达式exp=表达式Lambda(body,param);
//编译它以便我们可以使用它
Func orderFunc=exp.Compile();

从您编辑的问题中,您似乎只希望能够按多个键进行排序。只需使用
.OrderBy()
后跟
.ThenBy()
即可轻松实现。我假设您在这里使用的是
IQueryable

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);
IQueryable查询=。。。;
IOrderedQueryable ordered=null;
foreach(entityKeys中的var键)
{
//来自Doggett的代码,用于为一个步骤构造lambda表达式
ParameterExpression param=表达式参数(类型为(E),“a”);
var body=Expression.TypeAs(
Expression.PropertyOrField(参数,键),
类型(i可比较);
var exp=表达式Lambda(body,param);
if(有序==null)
ordered=query.OrderBy(exp);
其他的
已订购=已订购。然后按(exp);
}
var finalQuery=(有序的??查询).Skip(n).Take(m);

您能否更具体地说明您要完成的任务?例如,您希望在其中使用选择器的上下文?“匿名”类型实际上是实体的键。我们不必对此匿名。:)使用p=>“field1,field2,field3”不会进行任何排序,因为您按字符串“field1,field2,field3”对每个值进行排序,因此它们都是相同的。您在某些字段上使用下划线,而不是在其他字段上使用下划线。你在称赞Jon Skeet的一个非常基本的函数调用。我得到的印象是,您通过粘贴来自不同人员的代码将其缝合在一起,并且没有费心去思考自己的问题……下划线是私有变量。当我使用它时,我会注意到其他代码。我会提出问题,所以当我自己花太长时间来解决问题时。在Timwi要求澄清问题之前,我没有发布该代码。我将添加该代码以演示我很快将要做的事情。:)因为我收到了一个逗号分隔的OrderBy字段列表,按照所需的顺序排列。我现在就去试试。:)
p => "field1,field2,field3"
    // 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();
        // 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();
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);