Default Equality Comparer对特殊字符的比较规则及LINQ排序疑问
问题:C# LINQ排序特殊字符不符合ASCII预期的原因
我在C#中编写了一段代码,通过LINQ对Person列表按LastName的首字符排序,但实际输出结果和基于ASCII十进制值的预期排序不符,想了解默认相等比较器如何处理特殊字符,以及导致该结果的原因。
代码实现
namespace LINQ_check { internal class Program { static void Main() { List<Person> people1 = LoadSampleData(); people1 = people1.OrderBy<Person, string>((Person i) => i.LastName.Substring(0, 1)).ToList(); Console.WriteLine("\n\n"); foreach (var VARIABLE in people1) { Console.WriteLine(VARIABLE.ToString()); } } public static List<Person> LoadSampleData() { var output = new List<Person>(); output.Add(new Person { FirstName = "0Tida", LastName = "](Combey", Birthday = Convert.ToDateTime("2/25/1970"), YearsExperience = 20 }); output.Add(new Person { FirstName = "Joe", LastName = ")Combey", Birthday = Convert.ToDateTime("2/25/1970"), YearsExperience = 12 }); output.Add(new Person { FirstName = "Sue", LastName = "Storm", Birthday = Convert.ToDateTime("1/3/1970"), YearsExperience = 1 }); output.Add(new Person { FirstName = "1Sara", LastName = "Jones", Birthday = Convert.ToDateTime("3/6/1970"), YearsExperience = 8 }); output.Add(new Person { FirstName = "Jamie", LastName = "0Doe", Birthday = Convert.ToDateTime("2/18/1970"), YearsExperience = 7 }); output.Add(new Person { FirstName = "Mary", LastName = "&Smith", Birthday = Convert.ToDateTime("1/23/1970"), YearsExperience = 16 }); output.Add(new Person { FirstName = "Mary", LastName = "&Smith", Birthday = Convert.ToDateTime("1/23/1970"), YearsExperience = 15 }); return output; } public static List<Person> LoadSampleData1() { var output = new List<Person>(); output.Add(new Person { FirstName = "aaa", LastName = "bbbb", Birthday = Convert.ToDateTime("2/25/1970"), YearsExperience = 20 }); output.Add(new Person { FirstName = "tttt", LastName = "linq", Birthday = Convert.ToDateTime("2/25/1970"), YearsExperience = 12 }); return output; } } public class Person { public string FirstName { get; set; } public string LastName { get; set; } public int YearsExperience { get; set; } public DateTime Birthday { get; set; } public string FullName => $"{FirstName} {LastName}"; public override string? ToString() { return $"{FirstName} {LastName} ({Birthday.ToString("dd/MM/yyyy")}): Experience {YearsExperience}"; } } }
实际执行输出
Joe )Combey (25/02/1970): Experience 12 0Tida ](Combey (25/02/1970): Experience 20 Mary &Smith (23/01/1970): Experience 15 Mary &Smith (23/01/1970): Experience 16 Jamie 0Doe (18/02/1970): Experience 7 1Sara Jones (06/03/1970): Experience 8 Sue Storm (03/01/1970): Experience 1
需要排序的首字符为:)、]、&、&、0、J、S。按ASCII十进制值预期顺序应为&、&、)、]等,但实际结果不符。
原因分析
默认比较器不基于ASCII值排序
C#中OrderBy默认使用的Comparer<string>.Default比较器,并非基于原始ASCII或Unicode码点排序,而是遵循当前线程的区域性(Culture)排序规则。这类规则会根据语言文化习惯调整字符的排序优先级,和纯ASCII码点顺序差异明显。
区域性排序的影响
不同区域性对符号的排序权重定义不同,比如在默认的en-US区域性中,)、]这类符号的排序优先级高于&,这就导致了你看到的和ASCII预期不符的结果。
实现ASCII/Unicode码点排序的方法
如果需要严格按字符的Unicode码点(ASCII字符等同于ASCII值)排序,只需在OrderBy中指定StringComparer.Ordinal比较器:
people1 = people1.OrderBy(p => p.LastName.Substring(0, 1), StringComparer.Ordinal).ToList();
StringComparer.Ordinal会直接比较字符的底层码点值,得到符合ASCII预期的排序结果。
内容的提问来源于stack exchange,提问作者Eric Movsessian
相关产品推荐
相关产品推荐

