我怎么能清理这个lambda?

时间:2011-05-26 17:13:26

标签: c# linq lambda linq-to-entities expression

我有一个表达式,我在几个LINQ查询中使用了几次,所以我把它分成了它自己的返回表达式的方法。函数的lambda部分看起来很乱。任何人都想破解重构并使其更具可读性和/或更小?

    private Expression<Func<Message, bool>> UserSelector(string username, bool sent)
    {
        return x => ((sent ? x.FromUser : x.ToUser).Username.ToLower() == username.ToLower()) && (sent ? !x.SenderDeleted : !x.RecipientDeleted);
    }

它正在做的快速英文描述是检查布尔值sent并根据该布尔值检查Message.FromUserMessage.ToUser

如果用户正在查看他/她的发件箱,sent为真,则会看到x.FromUser.Username == usernamex.SenderDeleted == false

如果用户正在查看他/她的收件箱,那么它会执行相同的逻辑,但发送的内容为false,它会检查x.ToUserx.RecipientDeleted

也许这是最简单的方法,但我愿意接受一些重构。

ANSWER EDIT

我真的很喜欢Davy8的答案,但我决定更进一步,用一个嵌套函数做两个表达式而不是一个表达式。现在我有以下方法:

    /// <summary>
    /// Expression to determine if a message belongs to a user.
    /// </summary>
    /// <param name="username">The name of the user.</param>
    /// <param name="sent">True if retrieving sent messages.</param>
    /// <returns>An expression to be used in a LINQ query.</returns>
    private Expression<Func<Message, bool>> MessageBelongsToUser(string username, bool sent)
    {
        return x => (sent ? x.FromUser : x.ToUser).Username.Equals(username, StringComparison.OrdinalIgnoreCase);
    }

    /// <summary>
    /// Expression to determine if a message has been deleted by the user.
    /// </summary>
    /// <param name="username">The name of the user.</param>
    /// <param name="sent">True if retrieving sent messages.</param>
    /// <returns>An expression to be used in a LINQ query.</returns>
    private Expression<Func<Message, bool>> UserDidNotDeleteMessage(string username, bool sent)
    {
        return x => sent ? !x.SenderDeleted : !x.RecipientDeleted;
    }

所以现在我的查询看起来像这样:

    /// <summary>
    /// Retrieves a list of messages from the data context for a user.
    /// </summary>
    /// <param name="username">The name of the user.</param>
    /// <param name="page">The page number.</param>
    /// <param name="itemsPerPage">The number of items to display per page.</param>
    /// <param name="sent">True if retrieving sent messages.</param>
    /// <returns>An enumerable list of messages.</returns>
    public IEnumerable<Message> GetMessagesBy_Username(string username, int page, int itemsPerPage, bool sent)
    {
        var query = _dataContext.Messages
            .Where(MessageBelongsToUser(username, sent))
            .Where(UserDidNotDeleteMessage(username, sent))
            .OrderByDescending(x => x.SentDate)
            .Skip(itemsPerPage * (page - 1))
            .Take(itemsPerPage);
        return query;
    }

    /// <summary>
    /// Retrieves the total number of messages for the user.
    /// </summary>
    /// <param name="username">The name of the user.</param>
    /// <param name="sent">True if retrieving the number of messages sent.</param>
    /// <returns>The total number of messages.</returns>
    public int GetMessageCountBy_Username(string username, bool sent)
    {
        var query = _dataContext.Messages
            .Where(MessageBelongsToUser(username, sent))
            .Where(UserDidNotDeleteMessage(username, sent))
            .Count();
        return query;
    }

我想说那些是非常英文可读的查询,谢谢你们!

参考:http://www.codetunnel.com/blog/post/64/how-to-simplify-complex-linq-expressions

3 个答案:

答案 0 :(得分:3)

将其拆分为单独的函数:

    private Expression<Func<Message, bool>> UserSelector(string username, bool sent)
    {
        return message=> InnerFunc(message, username, sent);
    }

    private static bool InnerFunc(Message message, string username, bool sent)
    {
        if(sent)
        {
            return string.Equals(message.FromUser.Username, username, StringComparison.InvariantCultureIgnoreCase) && !message.SenderDeleted;
        }
        return string.Equals(message.ToUser.Username, username, StringComparison.InvariantCultureIgnoreCase) && !message.RecipientDeleted;
    }

或者可以内联以保持闭包使用:

    private Expression<Func<Message, bool>> UserSelector(string username, bool sent)
    {
        Func<Message, bool> innerFunc = message =>
        {
            if (sent)
            {
                return string.Equals(message.FromUser.Username, username, StringComparison.InvariantCultureIgnoreCase) &&
                        !message.SenderDeleted;
            }
            return string.Equals(message.ToUser.Username, username, StringComparison.InvariantCultureIgnoreCase) &&
                    !message.RecipientDeleted;
        };
        return message => innerFunc(message);
    }

(编辑使用string.Equals StringComparison.InvariantCultureIgnoreCase用于具有不同文化设置的奇数边缘情况。)

答案 1 :(得分:0)

你有Resharper吗?很多时候我会写这样的东西作为foreach循环,看看Resharper是否可以重构它。我认为可读性是最重要的,尽管你应该评估你提出的任何解决方案的性能。

答案 2 :(得分:0)

只要您将为此问题撰写的说明作为评论撰写,它应该有助于任何人尝试阅读/理解它是正确的吗?