本地化踩坑(2):xx.Parse函数

24 阅读2分钟

在游戏开发中,经常需要将字符串转换为目标类型。

例如,当使用 CSV 作为游戏配置表时,通常需要将字符串字段转换为相应的数据类型。

C# 提供了方便的 Parse 系列方法,许多基础类型都实现了它们。

然而,直接使用 Parse 方法在某些情况下会遇到区域性(culture)相关的问题,容易在上线后通过玩家反馈才被发现。

下面通过一个例子来说明这个问题以及解决办法。

假设我们有一个csv配置表,内容如下:

IDNamePriceIsAvailableExpiryTime
1HealthPot9.99true2024-12-31 23:59:59
2ManaPot14.50false2025-01-15 12:00:00

我们定义一个Item类来表示配置表中的数据:

public class Item
{
    public int ID { getset; }
    public string Name { getset; }
    public float Price { getset; }
    public bool IsAvailable { getset; }
    public DateTime ExpiryTime { getset; }

    public static Item Parse(string csvLine)
    {
        var parts = csvLine.Split(',');
        return new Item
        {
            ID = int.Parse(parts[0]),
            Name = parts[1],
            Price = float.Parse(parts[2]), // 这里可能会有区域性问题
            IsAvailable = bool.Parse(parts[3]),
            ExpiryTime = DateTime.Parse(parts[4]) // 这里也可能会有区域性问题
        };
    }
}

在上面的代码中,Price字段使用了float.Parse方法,ExpiryTime字段使用了DateTime.Parse方法。

如果游戏运行环境的区域设置不是我们预期的(比如小数点符号不同,日期格式不同),那么Parse方法可能会抛出异常或者解析出错误的值。

为了解决这个问题,我们可以在Parse方法中显式指定区域性信息,使用CultureInfo.InvariantCulture来确保解析行为一致:

using System.Globalization;
public static Item Parse(string csvLine)
{
    var parts = csvLine.Split(',');
    return new Item
    {
        ID = int.Parse(parts[0], CultureInfo.InvariantCulture),
        Name = parts[1],
        Price = float.Parse(parts[2], CultureInfo.InvariantCulture), // 指定区域性
        IsAvailable = bool.Parse(parts[3]),
        ExpiryTime = DateTime.Parse(parts[4], CultureInfo.InvariantCulture) // 指定区域性
    };
}

总结

通过显式指定区域性信息,我们可以避免由于不同区域设置导致的Parse方法行为不一致的问题,从而确保游戏配置数据能够正确解析和使用。

举一反三:类似的区域性问题也可能出现在字符串格式化(ToString方法)中,尤其是在处理数字和日期时间时。确保在格式化时也使用CultureInfo.InvariantCulture,以保持一致性。