这是暂时改变当前线程文化的好方法吗?

时间:2011-04-26 15:57:12

标签: c# .net localization cultureinfo

我在一个相当大的ASP .NET Web Forms应用程序上工作,该应用程序目前主要在美国使用。我们正在将其推广到世界其他地区,这当然意味着我们正在努力本地化应用程序的所有领域。一般来说,我们的方法是在每个请求开始时设置当前线程的CurrentCulture和CurrentUICulture属性,以支持基于当前用户的语言环境进行正确的格式化和资源提取。

但是,在某些情况下,我们需要使用除当前用户文化之外的文化来运行某些代码。例如,“用户A”居住在德国,但适用于与法国其他公司有业务往来的公司。当“用户A”想要为其中一家法国公司创建发票(PDF)时,我们希望发票生成代码以“fr-FR”文化而非“de-DE”文化运行。

我已经考虑过几种方法可以很容易地做到这一点,我想知道我是否正确地做到了这一点。我主要关心的是性能和线程安全性。

一种方法涉及一种静态方法,旨在使用提供的文化运行给定任务。像这样:

 public static void RunWithCulture(CultureInfo culture, Action task)
    {
        if (culture == null)
            throw new ArgumentNullException("culture");

        var originalCulture = new
                                  {
                                      Culture = Thread.CurrentThread.CurrentCulture,
                                      UICulture = Thread.CurrentThread.CurrentUICulture
                                  };

        try
        {
            Thread.CurrentThread.CurrentCulture = culture;
            Thread.CurrentThread.CurrentUICulture = culture;
            task();
        }
        finally
        {
            Thread.CurrentThread.CurrentCulture = originalCulture.Culture;
            Thread.CurrentThread.CurrentUICulture = originalCulture.UICulture;
        }
    }

然后可以像这样调用此方法:

var customerCulture = new CultureInfo(currentCustomer.Locale);
CultureRunner.RunWithCulture(customerCulture, () => invoiceService.CreateInvoice(currentCustomer.CustomerId));

我还考虑创建一个实现IDisposable的类,它负责在它的ctor中设置线程文化,然后在Dispose方法中返回原始文化,所以你可以像这样调用它:

var customerCulture = new CultureInfo(currentCustomer.Locale);
using(new CultureRunner(currentCustomer.Locale))
{
  invoiceService.CreateInvoice(currentCustomer.CustomerId);
}

我是否认为这一切都错了?哪个,如果这些方法中的任何一个更可取?

2 个答案:

答案 0 :(得分:15)

我喜欢using方法。我还创建了一个扩展方法,以便更好地阅读:

var customerCulture = new CultureInfo(currentCustomer.Locale);  
using (customerCulture.AsCurrent()) {
  invoiceService.CreateInvoice(currentCustomer.CustomerId);
}

这样的事情:

public static class CultureInfoExtensions {
  public static IDisposable AsCurrent(this CultureInfo culture) {
    return new CultureRunner(culture);
  }
}

或者,如果始终是您的客户对象设置文化,另一种扩展方法将进一步提升抽象:

using (currentCustomer.CultureContext()) {
  invoiceService.CreateInvoice(currentCustomer.CustomerId);
}

答案 1 :(得分:2)

既然你在问临时改变当前线程的文化是否好主意,我只能回答:没有。只有在没有其他办法让事情发挥作用的情况下才可以使用它。这只是因为这种切换容易出错。好的,你不会忘记用Jordão(尊重)给你的代码改回来,但是......
目前,您的客户想要创建法国发票。我假设你想使用法国日期,数字和货币格式。没关系。但是......如果将来某些未来需要以其他格式打印出来,例如这种原始德语,会怎么样?你打算创造一些丑陋的工作吗?

我知道它可能超出您的控制范围(如报告软件可能是3 rd 派对独立解决方案,您无法控制它如何处理ToString())但如果它在你的控制范围内,我建议首先以正确的格式提供数据。例如,您可以正确创建一些数据转换层(DTO)和格式数据(通过ToString(IFormatProvider))。我知道这是一项非常努力,但是因为你在询问正确的做事方式......

如果我们在同一个组织中并且我会进行I18n代码审查,那么您可以确定我会指出暂时改变文化作为缺陷。通常有一种方法可以避免这种情况。