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);