检测Lambda表达式是否用于对象属性

3

我正在尝试通过传递需要加载的子对象表达式来在存储库中实现一种急切加载功能。

    Candidate Get(int candidateId, params Expression<Func<Candidate, object>>[] includes);

那么我的服务可以像这样调用:

        candidateRepository.Get(1, p => p.Notes, p => p.Profile, p => p.Application);

“笔记”、“个人资料”和“应聘申请”都是“候选人”属性的一部分。例如:

    public class Candidate
    {
        public string Name { get; set; }

        public IList<CandidateNote> Notes { get; set; }

        public Profile Profile { get; set; }

        public Application Application { get; set; }
    }

所以,在存储库内,我需要确定是否传递了属性到表达式参数中以实际尝试水合化它。但是我没有看到一种优雅的方式来实现这一点。
    public Candidate Get(int candidateId, params Func<Candidate, object>[] includes)
    {
        ...

        if (candidate.Notes property was specified?)
        {
           candidate.Notes = this.candidateNoteRepository.List(candidateId);
        }

        return candidate;
    }

似乎我可以通过表达式 (includes[0].Body as MemberExpression).Member.Name 获取属性名称,但是似乎应该有更简单的方法。而且我不喜欢字符串比较。除非没有其他办法,否则我真的不想这样做:

        if (includes[0].Body as MemberExpression).Member.Name == "Notes")
        {

似乎这应该是非常简单的东西,例如:
        if (includes[0].Is(candidate.Notes) or includes[0](candidate.Notes).Match())
        {

如果出现这种情况,我非常希望将includes保留为Expression数组,因为尽管我今天正在使用ADO.NET,但我们计划最终采用Entity Framework,并且这些表达式将非常适用于Include方法。

        return this.Filter(m => m.Candidates.CandiateId == candidateId)
            .Include(includes[0])

最好是根据MemberExpression表达式中的MemberInfo对象获取/填充属性,而不是尝试为所有属性硬编码所有这些if语句。 - Servy
2个回答

1
你可能不希望这样做。这会强制您在编译时指定所有属性值,这将既繁琐又容易出错,并且不够灵活。
相反,最好只是从表达式中获取MemberInfo对象,然后使用它来获取该成员的值并设置给定对象的该成员的值。
首先使用一个帮助程序从遵循您已显示的模式的表达式中获取MemberInfo对象:
public static MemberInfo GetMemberInfo(LambdaExpression expression)
{
    var body = expression.Body as MemberExpression;
    if (body == null)
        return null;
    else
        return body.Member;
}

然后,您可以获取需要提取的成员对象集合:
var members = includes.Select(selector => GetMemberInfo(selector))
    .Where(member => member != null)
    //this validates the member is from the type itself; 
    //remove if such validation isn't desired
    .Intersect(typeof(Candidate).GetMembers());

然后通过查询或其他方式获取所有这些成员的值。

然后创建您的新对象,并填充每个成员的值:

var newItem = new Candidate();

foreach(var member in members)
{
    //Note that GetValueForMember shouldn't be doing a query.
    //it should be getting getting the value from the results
    member.SetValue(newItem, GetValueForMember(member));
}

0

正如您所说:字符串比较并不是一个好的方法,因为它不容易扩展。您可以更仔细地检查成员,以确定它是否是有效的包含。
一种选择是查看属性的返回类型。如果它派生自IEnumerable,则可能是有效的包含。
如果您在属性本身中找不到基于决策所需的必要事实,您可以使用自定义属性来标记类中的包含属性。然后,您可以检查可能包含的CustomAttributes属性,以确定它是否是有效的包含。


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