我该如何清理这个 lambda?
我有一个在多个 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.FromUser
或 Message.ToUser
那个布尔值。
如果用户正在查看他/她的发件箱,则 sent
为 true,并且它将查看是否 x.FromUser.Username == username
和 x.SenderDeleted ==假
。
如果用户正在查看他/她的收件箱,那么它会执行相同的逻辑,但发送是错误的,并且它会检查 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-表达式
I have an expression that I use a few times in several LINQ queries so I separated it out into it's own method that returns the expression. The lambda portion of the function is kind of messy looking. Anyone want to take a crack at refactoring it and making it more readable and/or smaller?
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);
}
A quick English description of what it's doing is it is checking the boolean sent
and checking either the Message.FromUser
or the Message.ToUser
based on that boolean.
If the user is looking at his/her outbox, sent
is true and it will see if x.FromUser.Username == username
and x.SenderDeleted == false
.
If the user is looking at his/her inbox then it does the same logic, but sent is false and it checks x.ToUser
and x.RecipientDeleted
instead.
Maybe this is the easiest way but I'm open to some refactoring.
ANSWER EDIT
I really liked Davy8's answer but I decided to take a step further and do two expressions instead of one expression with a nested function. Now I have the following methods:
/// <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;
}
So now my queries look like this:
/// <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;
}
I would say those are some very English readable queries, thanks guys!
Reference: http://www.codetunnel.com/blog/post/64/how-to-simplify-complex-linq-expressions
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
将其拆分为一个单独的函数:
或者可以将其内联以维护闭包用法:(
编辑为将
string.Equals
与StringComparison.InvariantCultureIgnoreCase
结合使用,用于具有不同的奇数边缘情况文化设置。)Split it out into a separate function:
Or alternatively it can be inlined to maintain closure usage:
(Edited to use
string.Equals
withStringComparison.InvariantCultureIgnoreCase
for odd edge cases with different culture settings.)你有Reshaper吗?很多时候我会写这样的东西作为 foreach 循环,看看 Resharper 是否可以重构它。不过,我认为可读性是最重要的,尽管您应该评估您提出的任何解决方案的性能。
Do you have Resharper? A lot of times I'll write something like this as a foreach loop and see if Resharper can refactor it. I think readability, though, is most important, although you should evaluate the peformance of any solution you come up with.
只要您将为此问题编写的描述写为评论,它就应该可以帮助任何试图阅读/理解它的人,正确吗?
As long as you write the description you wrote for this question as a comment, it should help anyone trying to read / understand it correct?