如何在运行时创建自定义Select lambda表达式以使用子类 [英] How do I create a custom Select lambda expression at runtime to work with sub classes

查看:71
本文介绍了如何在运行时创建自定义Select lambda表达式以使用子类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我具有以下类型层次结构:

If I have following type hierarchy:

abstract class TicketBase
{
    public DateTime PublishedDate { get; set; }
}

class TicketTypeA:TicketBase
{
     public string PropertyA { get; set; }
}   

class TicketTypeB:TicketBase
{
     public string PropertyB { get; set; }
}

还有更多TicketTypes : TicketBase

,并想创建一个选择任何属性的函数,例如任何票证类型的PropertyA TicketTypeA

and want to create a function which selects any property e.g. PropertyA from any ticket type e.g. TicketTypeA

我写了这个函数:

    private Func<TicketBase, String> CreateSelect(Type t, String FieldName)
    {
        var parameterExp = Expression.Parameter(t, "sel");
        var fieldProp = Expression.PropertyOrField(parameterExp, FieldName);
        var lambda = Expression.Lambda<Func<TicketBase, String>>(fieldProp, parameterExp);
        return lambda.Compile();
    }

并像这样在List<TicketBase> Tickets上调用它:

Type typeToSelectFrom = typeof(TicketTypeA);
String propertyToSelect = "PropertyA";
Tickets.Select(CreateSelect(typeToSelectFrom, propertyToSelect));

我收到以下ArgumentException:

I get the following ArgumentException:

ParameterExpression of type 'TicketTypes.TicketTypeA' cannot be used for delegate parameter of type 'Types.TicketBase'

有人知道如何解决这个问题吗?

Anyone know how to fix this?

推荐答案

好吧,一个选项包括一个强制类型转换,例如

Well, one option is to include a cast, e.g.

private Func<TicketBase, String> CreateSelect(Type t, String FieldName)
{
    var parameterExp = Expression.Parameter(typeof(TicketBase), "sel");
    var cast = Expression.Convert(parameterExp, t);
    var fieldProp = Expression.PropertyOrField(cast, FieldName);
    var lambda = Expression.Lambda<Func<TicketBase, String>>(fieldProp,
                                                             parameterExp);
    return lambda.Compile();
}

因此调用CreateSelect(typeof(TicketTypeA), "PropertyA")等效于:

Func<TicketBase, string> func = tb => ((TicketTypeA)tb).PropertyA;

很明显,如果将其应用于引用(例如)TicketTypeBTicketBase值,这将失败,但是如果您具有List<TicketBase>或类似名称,则很难避免这种情况.

Obviously that's going to fail if you apply it to a TicketBase value which refers to (say) a TicketTypeB, but it's hard to avoid that, if you've got a List<TicketBase> or something similar.

这篇关于如何在运行时创建自定义Select lambda表达式以使用子类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆