Как я могу очистить эту лямбду? - PullRequest
5 голосов
/ 26 мая 2011

У меня есть выражение, которое я использую несколько раз в нескольких запросах LINQ, поэтому я разделил его на собственный метод, который возвращает выражение.Лямбда-часть функции выглядит беспорядочно.Кто-нибудь хочет попробовать его рефакторинг и сделать его более читабельным и / или меньшим?

    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.FromUser или Message.ToUser на основе этого логического значения.

Если пользователь смотрит на свой почтовый ящик, sent имеет значение true, и он увидит, если x.FromUser.Username == username и x.SenderDeleted == false.

Если пользователь просматривает свой почтовый ящик, он выполняет ту же логику, но отправляет ложь и вместо этого проверяет x.ToUser и x.RecipientDeleted.

Возможно, это самый простой способ, но яЯ открыт для некоторого рефакторинга.

ОТВЕТ РЕДАКТИРОВАТЬ

Мне очень понравился ответ 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 ]

3 голосов
/ 26 мая 2011

Разделите его на отдельную функцию:

    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 для странных случаев с разными настройками культуры.)

0 голосов
/ 26 мая 2011

Пока вы пишете описание, которое вы написали для этого вопроса, в качестве комментария, оно должно помочь любому, кто пытается прочитать / понять его правильно?

0 голосов
/ 26 мая 2011

У вас есть Resharper?Много раз я буду писать что-то вроде этого как цикл foreach и посмотрим, сможет ли Resharper его реорганизовать.Я думаю, что удобочитаемость, тем не менее, является наиболее важной, хотя вам следует оценить эффективность любого решения, которое вы придумали.

...