从表达式函数中获取父级属性

6

假设我有以下类:

public class Model {
    public AnotherModel InnerModel {
        get;
        set;
    }
}

public class AnotherModel {
    public String Value{
        get;
        set;
    }
}

现在我有以下的函数:

public static void Foo<T, U>(Expression<Func<T, U>> func) {
     // Get the property info from func
}

现在我想做的是以下几点:

Foo<Model, String>(o => o.InnerModel.Value)

问题来了:

我知道你可以通过以下方式从表达式func中获取PropertyInfo:

PropertyInfo propertyInfo = (PropertyInfo)((MemberExpression)func.Body).Member;

这将为我获取Value属性的PropertyInfo。然而,我还想获取关于父属性InnerModel的信息。
目前我所知道的是可以执行以下操作:
((MemberExpression)func.Body).Expression

想要获取父属性的信息。然而,似乎无法从表达式本身中提取PropertyInfo。

有没有一种实际检索Expression的PropertyInfo的方法?

编辑: 为了澄清,可能是一种不好的尝试,但是这里有: 我不能使用EntityFramework来完成这个,只是为了确保这一点被理解。

有一个需要通过API与之通信的数据库。

此数据库具有常规关系,如以下方式: Table Thread UserID -> Users.UserID

现在提取到模型中。按照上面的例子:

class Thread {
    [Reference(USER_USERID)]
    [TableKey(THREAD_USERID)]
    public User user {
        get;set;
    }
}

class User {
     [TableKey(USER_USERID)]
     public int UserId {
         get;set;
     }
}

现在我想对此进行查询。所以我想:“嘿,使用表达式来简化最终用户询问的方式,好啊!”

因此,我们可以做一些像EqualTo(o => o.user.UserId,1)的事情。

然而,由于TableKey属性与参考键不同,我需要先从Thread表中获取userId,然后使用该Id开始向User表请求具有该id的信息。

也许这澄清了所有这些的目的,也可能没有。


如果您尝试以这种方式获取信息,那么您正在强制接受lambda调用参数的属性的属性,并且做任何其他事情都会破坏您的代码。在更高层次上,您实际上是想用这个表达式做什么?很可能有更好的方法来获得所需的信息,而不限制lambda所需的确切格式。 - Servy
那么你肯定需要以更通用的方式解决这个问题。听起来你正在从头开始编写整个查询提供程序。这是一个非常复杂、非常耗时/繁琐的过程。在SO答案的范围内,真的没有任何方法可以描述如何适当地解决这个问题。 - Servy
1
@Ekenstein 我不明白这个解决方案是如何尝试解决那个问题的...?那个问题听起来也相当广泛,不适合在SO上讨论。 - Adam Houldsworth
@Ekenstein 如果你在我删除回答之前看到了它,那么那是一个获取你想要内容的方法。鉴于评论,我认为这个问题应该被关闭。 - Adam Houldsworth
编辑了帖子以澄清。 - Ekenstein
1个回答

8

正如您已经确定的那样,表达式的主体是MemberExpression。我们需要查看MemberExpression的两个属性。

第一个是Member属性。这是正在调用的MemberInfo。在您的示例中,这是Value属性。我们需要查看的第二个属性是Expression属性。这是对成员表达式的调用。在您的示例中,这是{o.InnerModel}。

{o.InnerModel}是另一个MemberExpression。Member是InnerModel,Expression是o。

以下是一些获取MemberInfos链的代码

public static void Foo<T, U>(Expression<Func<T, U>> func)
{
    var memberExp = func.Body as MemberExpression;
    while (memberExp != null)
    {
        var memberInfo = memberExp.Member;
        Console.WriteLine(memberInfo.Name);
        memberExp = memberExp.Expression as MemberExpression;
    }
}

当像这样调用时:
Foo<Model, String>(o => o.InnerModel.Value);

它将输出:

  • 内部模型

这个:

Foo<Assembly, int>(a => a.EntryPoint.DeclaringType.AssemblyQualifiedName.Length);

将输出:

  • 长度
  • 程序集限定名
  • 声明类型
  • 入口点

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接