首页 > 解决方案 > C#:属性与常量的不同字符串编码

问题描述

我正在为一个旨在删除无效代码点(例如孤立代理对)的函数编写测试。但是,我发现代理对的编码方式有所不同,具体取决于我编写测试的方式。

虽然此版本的测试通过:

        [TestCategory("UnitTest")]
        [TestMethod]
        public void RemoveOrhpanedSurrogatePair()
        {
            var input = "\uDDDD1975";
            var cleanText = input.ReplaceInvalidCodePoints();

            Assert.AreEqual(input.Length - 1, cleanText.Length);
            Assert.AreEqual("1975", cleanText);
        }

这个没有:

        [TestCategory("UnitTest")]
        [TestMethod]
        [DataRow("\uDDDD1975")]
        public void RemoveOrhpanedSurrogatePair(string input)
        {
            var cleanText = input.ReplaceInvalidCodePoints();

            Assert.AreEqual(input.Length - 1, cleanText.Length);
            Assert.AreEqual("1975", cleanText);
        }

查看调试器,第一个变体将字符串编码为,"\uDDDD1975"但第二个变体产生的字符串"��1975"显示为两个有效字符,而不是一个孤立的代理对。

标签: c#stringunicodeencoding

解决方案


我认为答案的线索可以在(除了)@jonskeet博客文章中找到。显然 C# 在任何地方都使用 UTF16 对字符串进行编码,除了在使用 UTF8 的 Attribute c'tors 中。编译器似乎看到这是一个孤立的代理对,并通过其 UTF8 值将其视为两个无效的 Unicode 字符。然后将它们替换为一对\uFFFD字符(Unicode 替换字符,用于在将二进制解码为文本时指示损坏的数据)。

[Description(Value)]
class Test
{
    const string Value = "\uDDDD";
 
    static void Main()
    {
        var description = (DescriptionAttribute)
            typeof(Test).GetCustomAttributes(typeof(DescriptionAttribute), true)[0];
        DumpString("Attribute", description.Description);
        DumpString("Constant", Value);
    }
 
    static void DumpString(string name, string text)
    {
        var utf16 = text.Select(c => ((uint) c).ToString("x4"));
        Console.WriteLine("{0}: {1}", name, string.Join(" ", utf16));
    }
}

将产生:

Attribute: fffd fffd
Constant: dddd

推荐阅读