考虑一下:
var propertyinfo = typeof(Customer).GetProperty(sortExpressionStr);
Type orderType = propertyinfo.PropertyType;
现在我要宣布
Func<int,orderType>
我知道它不可能是直接的,因为ordertype
在运行时但有任何解决方法吗?
这正是我想要做的事情:
var propertyinfo = typeof(T).GetProperty(sortExpressionStr);
Type orderType = propertyinfo.PropertyType;
var param = Expression.Parameter(typeof(T), "x");
var sortExpression = (Expression.Lambda<Func<T, orderType>>
(Expression.Convert(Expression.Property(param, sortExpressionStr), typeof(orderType)), param));
这一切都是因为我想转换:
Expression<Func<T,object>> to Expression<Func<T,orderType>>
或者如果它不可能那么我想从正确的类型的第一个地方创建它,案例如下:
我在一个方法里面有一个type(Customer)
和一个我希望按其订购的类型的属性名称,我想创建一个排序表达式树来将它传递给Orderby
(这里) )。
答案 0 :(得分:7)
您可以使用Type.MakeGenericType Method:
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));
}
来自here。
答案 1 :(得分:7)
您可以使用开放的泛型类型定义,然后从中创建特定类型:
typeof(Func<,>).MakeGenericType(typeof(int), orderType);
但是,您尝试做的事情(调用Lambda<TDelegate>
)不是直接可行的。您必须在没有类型参数的情况下调用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);
如果您想在OrderBy
上调用Queryable
扩展程序,事情就会变得复杂一些:
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 });
答案 2 :(得分:1)
您希望使用Dynamic Linq,它是Visual Studio示例代码的一部分。
答案 3 :(得分:0)
如果您愿意,可以获得与Type
相关联的Func<int,orderType>
。将其传递给CreateDelegate。
但是你最终想要用它做什么?可能有一种更直接的方法。
答案 4 :(得分:0)
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;
}
这工作我的问题是我用来传递额外的参数Typeof(Object)和orderby用来告诉我它不能按对象类型排序。谢谢所有
感谢dtb我会检查你的答案是否也能正常工作,如果不能,我会接受它,如果不能,我会接受你的答案。
答案 5 :(得分:0)
查看我的解决方案是否足够动态。
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() });
}
基于上述内容,将Product
更改为T
以使其成为通用名称并不困难。