声明 Func动态地

发布于 2024-09-24 07:47:07 字数 944 浏览 4 评论 0原文

考虑一下:

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 (此处) 。

Consider this:

var propertyinfo = typeof(Customer).GetProperty(sortExpressionStr);
Type orderType = propertyinfo.PropertyType;

now I want to declare

Func<int,orderType>

I know its not possible directly since ordertype is at runtime but is there is any workaround ?

this is exactly what I want to do :

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

all this because I want to convert:

Expression<Func<T,object>> to Expression<Func<T,orderType>>

or if its not possible then I want to create it from the first place with the right type , the case is as following:

I'm inside a method which have a type(Customer) and a property name of that type I want to order by it , I want to create a sort expression tree to pass it to Orderby (here).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

醉殇 2024-10-01 07:47:07

您可以通过使用开放泛型类型定义来实现此目的,然后从中创建特定类型:

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

You can do this by using an open generic type definition, and then making the specific type from that:

typeof(Func<,>).MakeGenericType(typeof(int), orderType);

However, what you're trying to do (calling Lambda<TDelegate>) is not directly possible. You must call Lambda without a type parameter:

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

This will create the proper Func<,> for you behind the scenes. If you want to compile the expression and use the delegate, you can only do this dynamically with

sortExpression.Compile().DynamicInvoke(param);

If you want to call the OrderBy extension method on Queryable, things get a little more complicated:

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 });
笑梦风尘 2024-10-01 07:47:07

您可以使用 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));
}

来自此处

You can use the Type.MakeGenericType Method:

Type result = typeof(Func<,>).MakeGenericType(typeof(int), orderType);

This should work:

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

From here.

赢得她心 2024-10-01 07:47:07
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,我会检查你的答案是否也有效,如果有效,我会接受它,如果不行,我会接受这个。

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

this worked my problem was i used to pass extra parameter Typeof(Object) and orderby used to tell me it cant sort by Object type. thanks all

thanks dtb i will check if your answer work too and i will accept it if it works if not i will accept thsi one.

溺渁∝ 2024-10-01 07:47:07

看看我的解决方案是否足够动态。

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 以使其通用并不困难。

See if my solution dynamic enough.

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

Base on above, it's not difficult to change Product to T to make it generic.

清风夜微凉 2024-10-01 07:47:07

您可以获取与 Func 关联的 Type,以防您想要将其传递到 创建委托

但您最终想用它做什么?可能有更直接的方法。

You can get the Type associated with Func<int,orderType> in case you wanted to e.g. pass it into CreateDelegate.

But what are you ultimately wanting to do with it? There may be a more straightforward approach.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文