无法理解为什么我的简单排序不能按预期工作。这是违规行:
return messages.OrderBy(o => o.MessageType)
.ThenBy(p => p.IsUrgent)
.ThenByDescending(p => p.Timestamp)
.ToList();
最后两个排序(紧急和时间戳)无法正常工作。我的结果可以通过IsUrgent或Timestamp排序,但不能同时排序。
我的最终结果应该是所有消息都按类型排序(其中只有3种类型是New,Saved,Deleted)。然后在每种类型中,首先有紧急消息,然后按时间戳排序。
更新
你要求提供更多信息,所以这里是
[TestMethod]
public void Messages_should_sort_correctly()
{
var contact = new Models.Contact(); //just to satisfy the object
var expectedOrder = new string[] { "5", "6", "12", "3", "10", "9", "4", "8", "11", "13", "2", "7", "1" };
var messages = new List<IMessage>
{
new Models.Message { FileName = "1", MessageType = MessageType.Deleted, Timestamp = 31, Contact = contact },
new Models.Message { FileName = "2", MessageType = MessageType.Deleted, Timestamp = 34, Contact = contact },
new Models.Message { FileName = "3", MessageType = MessageType.Inbox, Timestamp = 11, Contact = contact },
new Models.Message { FileName = "4", MessageType = MessageType.Saved, Timestamp = 25, Contact = contact },
new Models.Message { FileName = "5", MessageType = MessageType.Inbox, Timestamp = 14, Contact = contact, IsUrgent = true },
new Models.Message { FileName = "6", MessageType = MessageType.Inbox, Timestamp = 13, Contact = contact, IsUrgent = true },
new Models.Message { FileName = "7", MessageType = MessageType.Deleted, Timestamp = 32, Contact = contact },
new Models.Message { FileName = "8", MessageType = MessageType.Saved, Timestamp = 22, Contact = contact },
new Models.Message { FileName = "9", MessageType = MessageType.Saved, Timestamp = 23, Contact = contact, IsUrgent = true },
new Models.Message { FileName = "10", MessageType = MessageType.Saved, Timestamp = 24, Contact = contact, IsUrgent = true },
new Models.Message { FileName = "11", MessageType = MessageType.Saved, Timestamp = 21, Contact = contact },
new Models.Message { FileName = "12", MessageType = MessageType.Inbox, Timestamp = 12, Contact = contact },
new Models.Message { FileName = "13", MessageType = MessageType.Deleted, Timestamp = 33, Contact = contact, IsUrgent = true }
};
messageServiceMock.Setup(m => m.GetAllMessagesAsync()).Returns(Task.FromResult(messages as IList<IMessage>)).AtMostOnce();
var result = service.Messages; //this property returns the messages from our mock, and then sorts and orders
var actualOrder = result.Select(m => m.FileName);
//expected order "5", "6", "12", "3", "10", "9", "4", "8", "11", "13", "2", "7", "1"
//actual order "12", "3", "5", "6", "4", "8", "11", "10", "9", "2", "7", "1", "13"
Assert.IsTrue(actualOrder.SequenceEqual(expectedOrder));
}
这里是所有魔法/混乱发生的地方
private List<Domain.Interfaces.IMessage> messages = new List<Domain.Interfaces.IMessage>();
public IList<Domain.Interfaces.IMessage> Messages
{
get
{
if (!messages.Any())
{
messages = messageService.GetAllMessagesAsync().Result.ToDomain().ToList();
}
return messages.OrderBy(o => o.MessageType).ThenBy(p => p.IsUrgent == true).ThenByDescending(p => p.Timestamp).ToList();
}
}
答案 0 :(得分:3)
理论上它应该按预期工作。您可以使用以下方式跟踪查询:
IQueryable<Message> query = messages
.OrderBy(o => o.MessageType)
.ThenBy(p => p.IsUrgent)
.ThenByDescending(p => p.Timestamp);
//debug query.ToString() to see the generated sql
//should be SELECT XXX WHERE YYY ORDER BY MessageType, IsUrgent, Timestamp DESC
return query.ToList();
答案 1 :(得分:2)
所以,现在混乱的根源很明显。当你对布尔进行排序时,首先得到false
值,然后得到true
个值。所以TS的配方要么是使用
return messages.OrderBy(o => o.MessageType)
.ThenByDescending(p => p.IsUrgent)
.ThenByDescending(p => p.Timestamp)
.ToList();
或
return messages.OrderBy(o => o.MessageType)
.Then(p => !p.IsUrgent)
.ThenByDescending(p => p.Timestamp)
.ToList();
Imo第一种方式更清晰,更直观,但这取决于你。
答案 2 :(得分:1)
快速调试显示这不是linq2objects的情况。
测试代码:
void Main()
{
var messages = GenerateTestData();
var results = messages.OrderBy(o => o.Type)
.ThenBy(p => p.IsUrgent)
.ThenByDescending(p => p.TimeStamp)
.ToList();
foreach (var m in results)
{
Console.WriteLine(m.ToString());
}
}
public List<Message> GenerateTestData()
{
var result = new List<Message>(10){
new Message(){ Type = MessageType.New, IsUrgent = true, TimeStamp = DateTime.Now.AddMilliseconds(10).Ticks},
new Message(){ Type = MessageType.Saved, IsUrgent = true, TimeStamp = DateTime.Now.AddMilliseconds(9).Ticks},
new Message(){ Type = MessageType.Deleted, IsUrgent = false, TimeStamp = DateTime.Now.AddMilliseconds(8).Ticks},
new Message(){ Type = MessageType.Deleted, IsUrgent = false, TimeStamp = DateTime.Now.AddMilliseconds(7).Ticks},
new Message(){ Type = MessageType.Saved, IsUrgent = false, TimeStamp = DateTime.Now.AddMilliseconds(6).Ticks},
new Message(){ Type = MessageType.New, IsUrgent = true, TimeStamp = DateTime.Now.AddMilliseconds(5).Ticks},
new Message(){ Type = MessageType.Saved, IsUrgent = true, TimeStamp = DateTime.Now.AddMilliseconds(4).Ticks},
new Message(){ Type = MessageType.Saved, IsUrgent = false, TimeStamp = DateTime.Now.AddMilliseconds(3).Ticks},
new Message(){ Type = MessageType.Deleted, IsUrgent = true, TimeStamp = DateTime.Now.AddMilliseconds(2).Ticks},
new Message(){ Type = MessageType.New, IsUrgent = false, TimeStamp = DateTime.Now.AddMilliseconds(1).Ticks}
};
return result;
}
public enum MessageType
{
New,
Saved,
Deleted
}
public class Message
{
public MessageType Type{get;set;}
public bool IsUrgent{get;set;}
public long TimeStamp {get;set;}
public override string ToString()
{
return string.Format("Type: {0}, IsUrgent: {1}, TimeStamp: {2}",this.Type, this.IsUrgent, this.TimeStamp);
}
}
导致以下完全正确和预期的结果
Type: New, IsUrgent: False, TimeStamp: 635922806855227531
Type: New, IsUrgent: True, TimeStamp: 635922806855317531
Type: New, IsUrgent: True, TimeStamp: 635922806855267531
Type: Saved, IsUrgent: False, TimeStamp: 635922806855277531
Type: Saved, IsUrgent: False, TimeStamp: 635922806855247531
Type: Saved, IsUrgent: True, TimeStamp: 635922806855307531
Type: Saved, IsUrgent: True, TimeStamp: 635922806855257531
Type: Deleted, IsUrgent: False, TimeStamp: 635922806855297531
Type: Deleted, IsUrgent: False, TimeStamp: 635922806855287531
Type: Deleted, IsUrgent: True, TimeStamp: 635922806855237531
我假设IsUrgent
是bool
而TimeStamp
是long
。
所以,我们肯定需要TS的更多细节。