Объявление Funcдинамично - PullRequest
       44

Объявление Funcдинамично

6 голосов
/ 20 сентября 2010

Учтите это:

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 ]

7 голосов
/ 20 сентября 2010

Вы можете сделать это, используя открытое определение универсального типа, а затем сделав из этого определенный тип:

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 });
7 голосов
/ 20 сентября 2010

Вы можете использовать метод Type.MakeGenericType :

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

С здесь .

1 голос
/ 20 сентября 2010

Вы хотите использовать 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

0 голосов
/ 20 сентября 2010

Посмотрите, достаточно ли динамично мое решение.

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, чтобы сделать его универсальным.

0 голосов
/ 20 сентября 2010
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, которые говорили мне, что он не может сортировать по типу Object. спасибо всем

спасибо, дтб, я тоже проверю, работает ли ваш ответ, и приму его, если он сработает, если нет, то приму этот.

0 голосов
/ 20 сентября 2010

Вы можете получить Type, связанный с Func<int,orderType>, если вы хотите, например, передать его в CreateDelegate .

Но что вы в конечном итоге хотите сделать с этим? Там может быть более простой подход.

...