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

时间:2015-09-07 11:19:18

标签: c# cultureinfo

要列出给定区域的适用文化,这是我目前的代码:

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

但我不想在RegionInfo中创建Where

我真的想做点什么:

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

但由于LCID RegionInfo上没有RegionInfo,我无法做到。除了更好的解决方案之外,了解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); } 会很有趣。

示例测试:

[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);
}

这适用于我目前的解决方案,但不适用于Jon。

对于Jon的修改解决方案(原创作品),另外两项测试失败了:

[code]
function PasswordContainsAtLeastOneSpecialChar(Pass : String) : Boolean;
var
    i : integer;
begin
    Result := false;

    for i:=1 to length(Pass) do
    begin
        case Pass[i] of
          '!', '"', '§', '$', '%', '&', '/', '(', ')', '=', '?', '\', '*', '#': // list all special characters here 
          begin
            Result := true;
            Exit;
          end;
        end;
    end;                           
end;

2 个答案:

答案 0 :(得分:4)

从查询中得到的结果应该非常明显 - 同一个区域可以有多个区域设置(因此也就是LCID)。所以充其量,你可以得到一个给定区域的LCID的列表 - 如果你想维护那个列表,那就自己动手吧。

例如,地区GB(英国)是三个不同语言区域的所在地 - cy-GB(1106),gd-GB(1169)和en-GB(2057)。

就性能而言,除非您可以避免所有分配在您的Where中,否则调整起来并不多。即使是简单的string.Split也可能比仅仅new RegionInfo花费更多。文化数据被缓存,因此在第一次之后只有与这种操作相关的内存成本。当然,如果你不记得内存成本,那么就没有什么能阻止你建立自己的查找。

答案 1 :(得分:0)

正如Jon Skeet指出的那样,RegionInfoName比较。当您从RegionInfo创建LCID时,该名称实际上来自CultureData找到的LCID上的媒体资源。

所以我添加了一个有效的扩展方法(至少在我的目的,即在我的解决方案中,我需要创建每个Region一次)从文化中获取区域名称。

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);
    }
}

用法:

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;
    }
}