C# 声明函数<;输入T,输出结果>;动态地
考虑这一点:C# 声明函数<;输入T,输出结果>;动态地,c#,lambda,expression-trees,predicate,anonymous-methods,C#,Lambda,Expression Trees,Predicate,Anonymous Methods,考虑这一点: var propertyinfo = typeof(Customer).GetProperty(sortExpressionStr); Type orderType = propertyinfo.PropertyType; 现在我要申报 Func<int,orderType> 所有这些都是因为我想转换: Expression<Func<T,object>> to Expression<Func<T,orderType>>
var propertyinfo = typeof(Customer).GetProperty(sortExpressionStr);
Type orderType = propertyinfo.PropertyType;
现在我要申报
Func<int,orderType>
所有这些都是因为我想转换:
Expression<Func<T,object>> to Expression<Func<T,orderType>>
表达式到表达式
或者,如果不可能,那么我想从第一个位置使用正确的类型创建它,情况如下:
我在一个方法中,该方法有一个类型(Customer)
和一个我想按其排序的该类型的属性名,我想创建一个排序表达式树,将其传递给Orderby
(此处)。您可以使用:
Type result=typeof(Func).MakeGenericType(typeof(int),orderType);
这应该起作用:
public static IQueryable<T> OrderByField<T>(
IQueryable<T> q, string sortfield, bool ascending)
{
var p = Expression.Parameter(typeof(T), "p");
var x = Expression.Lambda(Expression.Property(p, sortfield), p);
return q.Provider.CreateQuery<T>(
Expression.Call(typeof(Queryable),
ascending ? "OrderBy" : "OrderByDescending",
new Type[] { q.ElementType, x.Body.Type },
q.Expression,
x));
}
公共静态IQueryable OrderByField(
IQueryable q,字符串sortfield,布尔升序)
{
var p=表达式参数(typeof(T),“p”);
var x=Expression.Lambda(Expression.Property(p,sortfield),p);
返回q.Provider.CreateQuery(
表达式调用(typeof(Queryable),
升序?“OrderBy”:“OrderByDescending”,
新类型[]{q.ElementType,x.Body.Type},
q、 表情,
x) );
}
从。您可以通过使用打开的泛型类型定义,然后根据该定义生成特定类型来执行此操作:
typeof(Func<,>).MakeGenericType(typeof(int), orderType);
这将在幕后为您创建适当的Func
。如果要编译表达式并使用委托,则只能使用
sortExpression.Compile().DynamicInvoke(param);
如果要调用Queryable
上的OrderBy
扩展方法,事情会变得更复杂一些:
var propertyInfo = typeof(T).GetProperty(sortExpressionStr);
Type orderType = propertyInfo.PropertyType;
// first find the OrderBy method with no types specified
MethodInfo method = typeof(Queryable).GetMethods()
.Where(m => m.Name == "OrderBy" && m.GetParameters().Length == 2)
.Single();
// then make the right version by supplying the right types
MethodInfo concreteMethod = method.MakeGenericMethod(typeof(T), orderType);
var param = Expression.Parameter(typeof(T), "x");
// the key selector for the OrderBy method
Expression orderBy =
Expression.Lambda(
Expression.Property(orderParam, propertyInfo),
orderParam);
// how to use:
var sequence = new T[0].AsQueryable(); // sample IQueryable
// because no types are known in advance, we need to call Invoke
// through relection here
IQueryable result = (IQueryable) concreteMethod.Invoke(
null, // = static
new object[] { sequence, orderBy });
您可以获取与
Func
关联的类型
,以防您想将其传递到
但你最终想用它做什么呢?可能有一种更直接的方法。linqClass.OrderBy(GetSortExpression(sortstr));
linqClass.OrderBy(GetSortExpression(sortstr));
public static Expression<Func<T,object>> GetSortExpression<T>(string sortExpressionStr)
{
var param = Expression.Parameter(typeof(T), "x");
var sortExpression = Expression.Lambda<Func<T, object>>(Expression.Property(param, sortExpressionStr), param);
return sortExpression;
}
公共静态表达式GetSortExpression(字符串sortExpressionStr)
{
var param=表达式参数(类型(T),“x”);
var sortExpression=Expression.Lambda(Expression.Property(param,sortExpressionStr),param);
返回排序表达式;
}
这解决了我的问题,我用它传递额外的参数Typeof(Object),orderby告诉我它不能按对象类型排序。谢谢大家
谢谢dtb,我将检查您的答案是否有效,如果有效,我将接受。如果无效,我将接受thsi one。您希望使用Visual Studio示例代码的一部分Dynamic Linq
查看我的解决方案是否足够动态
public class Product
{
public long ID { get; set; }
public string Name { get; set; }
public DateTime Date { get; set; }
}
static void Main(string[] args)
{
List<Product> products = (from i in Enumerable.Range(1, 10)
select new Product { ID = i, Name = "product " + i, Date = DateTime.Now.AddDays(-i) }).ToList(); //the test case
const string SortBy = "Date"; // to test you can change to "ID"/"Name"
Type sortType = typeof(Product).GetProperty(SortBy).PropertyType; // DateTime
ParameterExpression sortParamExp = Expression.Parameter(typeof(Product), "p"); // {p}
Expression sortBodyExp = Expression.PropertyOrField(sortParamExp, SortBy); // {p.DateTime}
LambdaExpression sortExp = Expression.Lambda(sortBodyExp, sortParamExp); // {p=>p.DateTime}
var OrderByMethod = typeof(Enumerable).GetMethods().Where(m => m.Name.Equals("OrderBy") && m.GetParameters().Count() == 2).FirstOrDefault().MakeGenericMethod(typeof(Product), sortType);
var result = OrderByMethod.Invoke(products, new object[] { products, sortExp.Compile() });
}
公共类产品
{
公共长ID{get;set;}
公共字符串名称{get;set;}
公共日期时间日期{get;set;}
}
静态void Main(字符串[]参数)
{
列出产品=(从可枚举范围(1,10)中的i开始)
选择新产品{ID=i,Name=“Product”+i,Date=DateTime.Now.AddDays(-i)}).ToList();//测试用例
const string SortBy=“Date”;//要进行测试,可以更改为“ID”/“Name”
Type sortType=typeof(Product).GetProperty(SortBy).PropertyType;//日期时间
ParameterExpression sortParamExp=Expression.Parameter(产品类型),“p”);/{p}
表达式sortBodyExp=Expression.PropertyOrField(SORTPAREMXP,SortBy);//{p.DateTime}
LambdaExpression sortExp=Expression.Lambda(sortBodyExp,sortparemxp);//{p=>p.DateTime}
var OrderByMethod=typeof(Enumerable).GetMethods().Where(m=>m.Name.Equals(“OrderBy”)&&m.GetParameters().Count()=2.FirstOrDefault().MakeGenericMethod(typeof(Product),sortType);
var result=OrderByMethod.Invoke(产品,新对象[]{products,sortExp.Compile()});
}
基于上述情况,将
产品
更改为T
以使其通用并不困难。您不能在编译时声明sortExpression
是表达式
类型,因为orderType
在编译时是未知的,而只有在运行时才知道。编译后,您希望如何使用lambda表达式?好吧,忘了sortexpression吧,有没有可能通过使用propertyname字符串进行排序?我已经扩展了我的答案。这似乎是同一个问题,这种方法保持类型安全。没有伙伴,typeof(orderType)不会编译,我尝试了alreadytypeof(orderType)是不符合逻辑的,因为您在编译时尝试键入,而在运行时尝试键入ordertype,我想我只是好奇:为什么需要表达式。在进行动态排序时,如果不知道要传递哪个属性,请将具有typeordertype
的属性转换为typeordertype
?@dtb!什么类型的它,当它作为一个字符串传递给您时,它不会太有效,鲁本,因为这样我就不能使用linqClass.OrderBy(这里)返回DynamicInvoke了;我不确定这是否符合我的情况,也不确定如何测试它,无论如何我都解决了这个问题,感谢无论如何dtb的时间和努力。@Stacker:那么,你是如何解决这个问题的?其他人可能会偶然发现你的问题,并遇到同样的问题。我已经发布了解决方案,并发布了代码中的错误。谢谢你buddyYes如果我使用linq来枚举,而不是linq来sql,我可以使用它,因为这会导致记录的排序,所以如果你只取前10个,跳过它会带来麻烦,因为你需要在重定时记录时使用orderby方法在sql中进行排序!是的,这会起作用,但我不想包含作为源文件而不是程序集分发的动态linq dllIt。您可以将其编译到程序集中,以避免任何额外的引用。看看C:\Program Files(x86)\Microsoft Visual Studio 10.0\Samples\1033\CSharpSamples.zip和压缩文件LinqSamples\DynamicQuery\DynamicQuery\DynamicQuery\Dynamic.cs这对我不起作用。列表=新列表()/*fill list*/当我这样调用时:list.OrderBy(GetSortExpression(“MyColName”))
var propertyInfo = typeof(T).GetProperty(sortExpressionStr);
Type orderType = propertyInfo.PropertyType;
// first find the OrderBy method with no types specified
MethodInfo method = typeof(Queryable).GetMethods()
.Where(m => m.Name == "OrderBy" && m.GetParameters().Length == 2)
.Single();
// then make the right version by supplying the right types
MethodInfo concreteMethod = method.MakeGenericMethod(typeof(T), orderType);
var param = Expression.Parameter(typeof(T), "x");
// the key selector for the OrderBy method
Expression orderBy =
Expression.Lambda(
Expression.Property(orderParam, propertyInfo),
orderParam);
// how to use:
var sequence = new T[0].AsQueryable(); // sample IQueryable
// because no types are known in advance, we need to call Invoke
// through relection here
IQueryable result = (IQueryable) concreteMethod.Invoke(
null, // = static
new object[] { sequence, orderBy });
linqClass.OrderBy(GetSortExpression(sortstr));
public static Expression<Func<T,object>> GetSortExpression<T>(string sortExpressionStr)
{
var param = Expression.Parameter(typeof(T), "x");
var sortExpression = Expression.Lambda<Func<T, object>>(Expression.Property(param, sortExpressionStr), param);
return sortExpression;
}
public class Product
{
public long ID { get; set; }
public string Name { get; set; }
public DateTime Date { get; set; }
}
static void Main(string[] args)
{
List<Product> products = (from i in Enumerable.Range(1, 10)
select new Product { ID = i, Name = "product " + i, Date = DateTime.Now.AddDays(-i) }).ToList(); //the test case
const string SortBy = "Date"; // to test you can change to "ID"/"Name"
Type sortType = typeof(Product).GetProperty(SortBy).PropertyType; // DateTime
ParameterExpression sortParamExp = Expression.Parameter(typeof(Product), "p"); // {p}
Expression sortBodyExp = Expression.PropertyOrField(sortParamExp, SortBy); // {p.DateTime}
LambdaExpression sortExp = Expression.Lambda(sortBodyExp, sortParamExp); // {p=>p.DateTime}
var OrderByMethod = typeof(Enumerable).GetMethods().Where(m => m.Name.Equals("OrderBy") && m.GetParameters().Count() == 2).FirstOrDefault().MakeGenericMethod(typeof(Product), sortType);
var result = OrderByMethod.Invoke(products, new object[] { products, sortExp.Compile() });
}