声明Func <in t,=“”out =“”result =“”>动态</in>

时间:2010-09-20 14:15:52

标签: c# lambda expression-trees predicate anonymous-methods

考虑一下:

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(这里) )。

6 个答案:

答案 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示例代码的一部分。

Example code using Dynamic Linq

http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

答案 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以使其成为通用名称并不困难。