You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 07:33:20