比较文化区域而不从 LCID 创建 RegionInfo

wes*_*ton 5 c# cultureinfo

为了列出给定区域的适用文化,这是我当前的代码:

public IEnumerable<CultureInfo> ForRegion(RegionInfo regionInfo)
{
     return CultureInfo.GetCultures(CultureTypes.SpecificCultures)
          .Where(c => Equals(new RegionInfo(c.LCID), regionInfo));
}
Run Code Online (Sandbox Code Playgroud)

但我不喜欢必须RegionInfoWhere.

我真的很想做这样的事情:

public IEnumerable<CultureInfo> ForRegion(RegionInfo regionInfo)
{
     return CultureInfo.GetCultures(CultureTypes.SpecificCultures)
          .Where(c => c.LCID == regionInfo.LCID);
}
Run Code Online (Sandbox Code Playgroud)

但因为没有,LCID所以RegionInfo我不能。除了更好的解决方案之外,了解为什么 aRegionInfo没有LCID.

测试示例:

[TestMethod]
public void Can_find_all_by_region_ES_valencia()
{
    var regionInfo = new RegionInfo(new CultureInfo("ca-ES-valencia").LCID);
    List<CultureInfo> found = ForRegion(regionInfo).ToList();
    Assert.AreEqual(5, found.Count);
    CollectionAssert.AreEqual(
        new[]
        {
            new CultureInfo("ca-ES"),
            new CultureInfo("ca-ES-valencia"), //missing with Jon's solution
            new CultureInfo("es-ES"),
            new CultureInfo("eu-ES"),
            new CultureInfo("gl-ES")
        },
        found);
}
Run Code Online (Sandbox Code Playgroud)

这适用于我当前的解决方案,但不适用于乔恩的解决方案。

另外两个测试,乔恩修改后的解决方案失败了(适用于原始解决方案):

[TestMethod]
public void Can_find_all_by_region_Germany()
{
    List<CultureInfo> found = ForRegion(new RegionInfo("DE")).ToList();
    Assert.AreEqual(3, found.Count);
    CollectionAssert.AreEqual(
        new[] {new CultureInfo("de-DE"), new CultureInfo("dsb-DE"), new CultureInfo("hsb-DE")}, found);
}

[TestMethod]
public void Round_trip_all_cultures()
{
    foreach (CultureInfo culture in CultureInfo.GetCultures(CultureTypes.SpecificCultures))
        Assert.IsTrue(ForRegion(new RegionInfo(culture.LCID)).Contains(culture), culture.Name);
}
Run Code Online (Sandbox Code Playgroud)

wes*_*ton 0

正如乔恩·斯基特(Jon Skeet)指出的,RegionInfos 是通过 进行比较的NameRegionInfo当您从 an创建 a 时LCID,该名称实际上来自CultureData它通过 找到的a 上的属性LCID

因此,我添加了一个扩展方法,可以有效地(至少出于我的目的,即在我的解决方案中,无论如何我都需要创建每个区域一次)从文化中获取区域名称。

public static class CultureInfoExtension
{
    private static readonly Dictionary<int, string> RegionNamesByLcid =
        CultureInfo.GetCultures(CultureTypes.SpecificCultures)
            .Select(c => c.LCID)
            .Distinct()
            .ToDictionary(lcid => lcid, lcid => new RegionInfo(lcid).Name);

    private static string FallbackToThrowConsistentException(CultureInfo c)
    {
        return new RegionInfo(c.LCID).Name;
    }

    public static string GetRegionName(this CultureInfo c)
    {
        string name;
        return RegionNamesByLcid.TryGetValue(c.LCID, out name)
            ? name
            : FallbackToThrowConsistentException(c);
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

public IEnumerable<CultureInfo> ForRegion(RegionInfo regionInfo)
{
    return CultureInfo.GetCultures(CultureTypes.SpecificCultures)
        .Where(c => CultureBelongsToRegion(c, regionInfo));
    }

    private static bool CultureBelongsToRegion(CultureInfo c, RegionInfo regionInfo)
    {
        return c.GetRegionName() == regionInfo.Name;
    }
}
Run Code Online (Sandbox Code Playgroud)