反射和继承问题c#

Reflection and inheritance issue c#

我正在尝试使用反射来确定结构所有部分的 MemberExpression。这些是说明问题的一些对象:

public class Entity
{
    public Part FirstPart { get; set; }
}

public class Part
{
    public int Id { get; set; }
}

public class SubPart : Part
{
    public int ExtraProperty { get; set; }
}

我用来确定每个组件的 MemberExpression 的函数适用于以下对象结构:

        Entity entity = new Entity() { FirstPart = new Part() { Id = 1 } };

函数为:

        var param = Expression.Parameter(entity.GetType());
        String[] childProperties = ("FirstPart.Id").Split('.');
        var propExpression = Expression.PropertyOrField(param, childProperties[0]);
        for (int i = 1; i < childProperties.Length; i++)
        {
            propExpression = Expression.PropertyOrField(propExpression, childProperties[i]);
        }

但是由于继承,这对以下对象不起作用:

        Entity entity = new Entity() { FirstPart = new SubPart() { ExtraProperty = 1 } };

为了追溯属性,我们需要将路径更改为 "FirstPart.ExtraProperty":

        var param = Expression.Parameter(entity.GetType());
        String[] childProperties = ("FirstPart.ExtraProperty").Split('.');
        var propExpression = Expression.PropertyOrField(param, childProperties[0]);
        for (int i = 1; i < childProperties.Length; i++)
        {
            propExpression = Expression.PropertyOrField(propExpression, childProperties[i]);
        }

错误消息指出:'ExtraProperty' 不是 Part 的成员。有谁知道如何解决这个问题?

你不能。将表达式视为代码,它是在运行时而不是编译时编译的。没有魔法和类似的规则适用(表达式是低级的且限制性更强,因此许多在 C# 代码级别可用的语法糖在表达式中不可用)。也就是说,由于 entity.FirstPart.ExtraProperty 在 C# 代码中无效,因此在表达式中也无效。

您可以插入显式强制转换 - 但是您假设实例实际上是 SubPart 类型,那么为什么不定义 SubPart 类型的成员 FirstPart 而不是Part。或者,您可以使用 TypeIs expression 创建类型测试逻辑,然后按照与在 C# 代码中相同的方式进行转换。

编辑:

重读你的问题后,我发现你实际上想实现的是 属性 遍历任意对象。所以 TypeIs 表达式在这里对你没有帮助,因为它需要你正在测试的类型在编译时是已知的。但是在您的情况下, FirstPart 成员中的 Part 可以有任意的 class 派生,具有任意附加属性。在这种情况下,没有其他选择,只能逐一评估每个 属性 访问并从中间值中检索实际类型。例如:

Entity entity = new Entity() { FirstPart = new SubPart() { ExtraProperty = 1 } };

object currentObjectInChain = entity;
String[] childProperties = ("FirstPart.ExtraProperty").Split('.');

foreach (var property in childProperties)
{
    if (currentObjectInChain == null)
    {
        throw new ArgumentException("Current value is null");
    }
    var type = currentObjectInChain.GetType();
    var param = Expression.Parameter(type);
    var lambda = Expression.Lambda(
        Expression.PropertyOrField(param, property),
        param).Compile(); // cache based on type and property name
    currentObjectInChain = lambda.DynamicInvoke(currentObjectInChain);
}

在循环结束时 currentObjectInChain 将保留您的值。