声明Func 动态
考虑一下:
var propertyinfo = typeof(Customer).GetProperty(sortExpressionStr); Type orderType = propertyinfo.PropertyType;
现在我想宣布
Func
我知道它不可能直接因为ordertype
是在运行时但有任何解决方法吗?
这正是我想要做的:
var propertyinfo = typeof(T).GetProperty(sortExpressionStr); Type orderType = propertyinfo.PropertyType; var param = Expression.Parameter(typeof(T), "x"); var sortExpression = (Expression.Lambda<Func> (Expression.Convert(Expression.Property(param, sortExpressionStr), typeof(orderType)), param));
这一切都是因为我想转换:
Expression<Func> to Expression<Func>
或者如果它不可能那么我想从正确的类型的第一个地方创建它,案例如下:
我在一个方法里面有一个type(Customer)
和一个我希望按其订购的类型的属性名称,我想创建一个排序表达式树来将它传递给Orderby
(这里)。
您可以使用Type.MakeGenericType方法 :
Type result = typeof(Func<,>).MakeGenericType(typeof(int), orderType);
这应该工作:
public static IQueryable OrderByField ( IQueryable 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 ( Expression.Call(typeof(Queryable), ascending ? "OrderBy" : "OrderByDescending", new Type[] { q.ElementType, x.Body.Type }, q.Expression, x)); }
从这里开始 。
您可以通过使用开放的generics类型定义,然后从中创建特定类型来执行此操作:
typeof(Func<,>).MakeGenericType(typeof(int), orderType);
但是,您正在尝试做的事情(调用Lambda
)是不可能的。 您必须在没有类型参数的情况下调用Lambda
:
var propertyinfo = typeof(T).GetProperty(sortExpressionStr); Type orderType = propertyinfo.PropertyType; var param = Expression.Parameter(typeof(T), "x"); var sortExpression = Expression.Lambda( Expression.Convert(Expression.Property(param, sortExpressionStr), orderType), param));
这将在幕后为您创建正确的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 });
您想使用Dynamic Linq,它是Visual Studio示例代码的一部分。
您可以获取与Func
关联的Type
,以防您想要将其传递给CreateDelegate 。
但是你最终想要用它做什么? 可能有一种更直接的方法。
linqClass.OrderBy(GetSortExpression(sortstr)); public static Expression> GetSortExpression(string sortExpressionStr) { var param = Expression.Parameter(typeof(T), "x"); var sortExpression = Expression.Lambda>(Expression.Property(param, sortExpressionStr), param); return sortExpression; }
这工作我的问题是我曾经传递额外的参数Typeof(对象)和orderby用于告诉我它不能按对象类型排序。 谢谢大家
谢谢dtb我会检查你的答案是否也能正常工作,如果不能,我会接受它,否则我会接受你的答案。
看看我的解决方案是否足够动态
public class Product { public long ID { get; set; } public string Name { get; set; } public DateTime Date { get; set; } } static void Main(string[] args) { List 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() }); }
基于上述内容,将Product
更改为T
以使其通用并不困难。