C#:区分 CurrentCulture 和 InvariantCulture 的单元测试

Posted

技术标签:

【中文标题】C#:区分 CurrentCulture 和 InvariantCulture 的单元测试【英文标题】:C#: Unit Test to Differentiate CurrentCulture from InvariantCulture 【发布时间】:2011-04-24 05:52:17 【问题描述】:

我有一个采用 StringComparison 参数的方法,它确实需要一个单元测试来证明它正在执行正确的比较类型。

这基本上是我目前所拥有的。它通过比较“oe”和“œ”来区分 Ordinal(参见System.String)。但是,我还没有找到区分 CurrentCulture 和 InvariantCulture 的方法。

using System;
using NUnit.Framework;
using System.Threading;
using System.Globalization;

namespace NUnitTests

    [TestFixture]
    public class IndexOfTests
    
        [Test]
        public void IndexOf_uses_specified_comparison_type()
        
            StringComparison comparisonTypePerformed;

            result = TestComparisonType(StringComparison.CurrentCulture);
            Assert.AreEqual(StringComparison.CurrentCulture, comparisonTypePerformed);

            result = TestComparisonType(StringComparison.InvariantCulture);
            Assert.AreEqual(StringComparison.CurrentCulture, comparisonTypePerformed);

            result = TestComparisonType(StringComparison.Ordinal);
            Assert.AreEqual(StringComparison.CurrentCulture, comparisonTypePerformed);
        

        bool TestComparisonType(StringComparison comparisonType)
        
            int result;

            // Ensure the current culture is consistent for test
            var prevCulture = Thread.CurrentThread.CurrentCulture;
            Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", false);

            try
            
                result = IndexOf("oe", "œ", comparisonType);
                if (result == 0)
                
                    // The comparison type performed was either CurrentCulture,
                    // InvariantCulture, or one of the case-insensitive variants.

                    // TODO: Add test to differentiate between CurrentCulture and InvariantCulture
                    throw new NotImplementedException();
                    result = IndexOf("???????", "???????", StringComparison.CurrentCulture);

                    //...
                
                else // result == -1
                
                    // The comparison type performed was either Ordinal or OrdinalIgnoreCase

                    result = IndexOf("a", "A", StringComparison.CurrentCulture);
                    if (result)
                        Console.WriteLine("Comparison type was OrdinalIgnoreCase");
                    else
                        Console.WriteLine("Comparison type was Ordinal");
                
            
            finally
            
                Thread.CurrentThread.CurrentCulture = prevCulture;
            
        
    

我曾考虑通过比较“i”和“I”来使用土耳其语问题,但它仅适用于不区分大小写的比较。

我环顾四周,在字符串相等性测试(仅排序顺序和解析/序列化)中找不到 InvariantCulture 与其他文化不同的情况。例如,根据文化,“ô”和“o”的排序方式不同,但所有文化在相等性测试中返回相同的结果。

是否有用于区分 InvariantCulture 与任何其他文化的平等测试?

编辑: 德语“ß”和“ss”对所有文化都给出相同的结果,因此它们不起作用。

编辑: 实际上,只需要两个字符串在一种文化中相等,而在另一种文化中不相等。

【问题讨论】:

【参考方案1】:

CultureInfo 上的 MSDN 示例有一个示例,该示例具有不同的排序顺序,具体取决于文化。我认为这是你最有可能作为起点的赌注。但是,如果这不起作用,您也许可以利用下面的一些信息。

似乎正在String.Compare MSDN 页面上执行一组类似的测试。但在此示例中,它是在 en-US 文化中。

如果您查看 CultureInfo.InvarientCulture 页面,您会注意到 InvarientCulture 基于英语,但没有任何区域或国家/地区编码。 StringComparison 页面提到连字符特别具有不同的权重,具体取决于语言。您可以通过找到一种与英语不同的连字符权重的语言来利用这一点。

***在collation 文章中有一些关于排序的有趣注释,这可能也很有用。通过排序,按字母顺序仔细查看,然后查看西班牙语注释。

例如,29 个字母的字母表 西班牙语将 ñ 视为基本字母 在 n 之后,以前处理过 ch 和 ll 作为 c 之后的基本字母 和 l,分别。 Ch 和 ll 是 仍然被认为是字母,但现在 按字母顺序排列为两个字母 组合。

我不确定这会有多大帮助,但它可能会引导您找到答案。

【讨论】:

谢谢!与不变的文化相比,Ch 和 ll 在某些文化中返回不同的结果。奇怪的是,在西班牙文化中却没有。我发布了一个答案,展示了这些差异,我目前必须将其标记为已接受的答案,但它是基于你的。【参考方案2】:

感谢 blackSphere,我能够找到一些文化和 InvariantCulture 之间的一些差异,如下面的代码所示:

void Demonstration_For_LL()

    int foundPos;

    foundPos = "ll".IndexOf("l", StringComparison.InvariantCulture);
    Assert.AreEqual(0, foundPos);

    Thread.CurrentThread.CurrentCulture = new CultureInfo("sq", false);
    foundPos = "ll".IndexOf("l", StringComparison.CurrentCulture);
    Assert.AreEqual(-1, foundPos);

    Thread.CurrentThread.CurrentCulture = new CultureInfo("sq-AL", false);
    foundPos = "ll".IndexOf("l", StringComparison.CurrentCulture);
    Assert.AreEqual(-1, foundPos);


void Demonstration_For_CH()

    int foundPos;

    foundPos = "ch".IndexOf("c", StringComparison.InvariantCulture);
    Assert.AreEqual(0, foundPos);

    Thread.CurrentThread.CurrentCulture = new CultureInfo("cs", false);
    foundPos = "ch".IndexOf("c", StringComparison.InvariantCulture);
    Assert.AreEqual(-1, foundPos);

    Thread.CurrentThread.CurrentCulture = new CultureInfo("cs-CZ", false);
    foundPos = "ch".IndexOf("c", StringComparison.InvariantCulture);
    Assert.AreEqual(-1, foundPos);

    Thread.CurrentThread.CurrentCulture = new CultureInfo("sk", false);
    foundPos = "ch".IndexOf("c", StringComparison.InvariantCulture);
    Assert.AreEqual(-1, foundPos);

    Thread.CurrentThread.CurrentCulture = new CultureInfo("sk-SK", false);
    foundPos = "ch".IndexOf("c", StringComparison.InvariantCulture);
    Assert.AreEqual(-1, foundPos);

    Thread.CurrentThread.CurrentCulture = new CultureInfo("vi", false);
    foundPos = "ch".IndexOf("c", StringComparison.InvariantCulture);
    Assert.AreEqual(-1, foundPos);

    Thread.CurrentThread.CurrentCulture = new CultureInfo("vi-VN", false);
    foundPos = "ch".IndexOf("c", StringComparison.InvariantCulture);
    Assert.AreEqual(-1, foundPos);

不幸的是,string.Compare 方法似乎没有显示这些差异。无论如何,我的测试方法现在看起来是这样的:

class Example

    public static void Main()
    
        var comparisonTypePerformed =
            GetComparisonTypePerformed(
                new TestedMethod(string.IndexOf));

        Console.WriteLine("Comparison type performed was: " + comparisonTypePerformed);
    

    public static StringComparison GetComparisonTypePerformed(TestedMethod testedMethod)
    
        StringComparison comparisonTypePerformed;

        var prevCulture = Thread.CurrentThread.CurrentCulture;
        try
        
            Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", false);

            // Check if method performs an Ordinal search
            int result = testedMethod("œ", "oe", 0, 1, comparisonType);

            if (result == StringHelper.NPOS)
            
                // Check if method performs a case-sensitive search
                result = testedMethod("a", "A", 0, 1, comparisonType);

                if (result == StringHelper.NPOS)
                    comparisonTypePerformed = StringComparison.Ordinal;
                else
                    comparisonTypePerformed = StringComparison.OrdinalIgnoreCase;
            
            else
            
                Thread.CurrentThread.CurrentCulture = new CultureInfo("sq-AL", false);

                // Check if method uses CurrentCulture or InvariantCulture
                result = testedMethod("ll", new string[]  "l" , 0, 2, comparisonType);

                if (result == StringHelper.NPOS)
                
                    // Check if method performs a case-sensitive search
                    result = testedMethod("a", new string[]  "A" , 0, 1, comparisonType);

                    if (result == StringHelper.NPOS)
                        comparisonTypePerformed = StringComparison.CurrentCulture;
                    else
                        comparisonTypePerformed = StringComparison.CurrentCultureIgnoreCase;
                
                else
                
                    // Check if method performs a case-sensitive search
                    result = testedMethod("a", new string[]  "A" , 0, 1, comparisonType);

                    if (result == StringHelper.NPOS)
                        comparisonTypePerformed = StringComparison.InvariantCulture;
                    else
                        comparisonTypePerformed = StringComparison.InvariantCultureIgnoreCase;
                
            
        
        finally
        
            Thread.CurrentThread.CurrentCulture = prevCulture;
        

        return comparisonTypePerformed;
    

    delegate int TestedMethod(string source, string value, int startIndex, int count, StringComparison comparisonType);

【讨论】:

【参考方案3】:

尝试以 fr-FR 作为您当前的文化的 cote 和 côte。

或使用this MSDN resource 查找其他示例。

我环顾四周,找不到 InvariantCulture 通过字符串比较(仅排序顺序和解析/序列化)与其他文化不同的情况。

我不明白这条评论 - 排序顺序肯定使用 StringComparison。

【讨论】:

é 和 ô 的排序因文化而异,但似乎不会影响平等测试,这正是我所需要的。我更新了问题以尝试更清楚。谢谢 @drifter - 您是否查看过 String.IndexOf 文档中的示例:msdn.microsoft.com/en-us/library/ms224425.aspx。它将字符串与 \u00c5 和 \u0061\u030a 进行比较。也许会给你你想要的。 该示例对 CurrentCulture 和 InvariantCulture 的结果相同。我在其他文化中尝试过它的变体,但没有运气。

以上是关于C#:区分 CurrentCulture 和 InvariantCulture 的单元测试的主要内容,如果未能解决你的问题,请参考以下文章

c# 赋值疑问

c# .net 面试总结

c#实现自然排序效果,按1,2,11而不是1,11,12,区分字母文字和数字

WPF XAML 绑定和 CurrentCulture 显示

.NET 中 CultureInfo 的 CurrentCulture 和 CurrentUICulture 属性有啥区别?

用于设置 CurrentCulture 的线程创建事件