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

标签 c# .net localization cultureinfo

我正在开发一个相当大的 ASP .NET Web 窗体应用程序,该应用程序目前主要在美国使用。我们正在将其推广到世界其他地区,这当然意味着我们目前正在努力对应用程序的所有领域进行本地化。一般来说,我们的方法是在每个请求开始时设置当前线程的 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 的类,该类负责在其构造函数中设置线程区域性,然后在 Dispose 方法中返回原始区域性,因此您可以这样调用它:

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

我是不是做错了?如果这些方法中的任何一种更可取,哪种方法更可取?

最佳答案

我喜欢使用的方法。我还会创建一个扩展方法来让内容更易读:

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

CultureRunner 示例:

public class CultureRunner : IDisposable
{
    readonly CultureInfo originalCulture;
    readonly CultureInfo originalUICulture;

    public CultureRunner(CultureInfo culture)
    {
        if (culture == null)
            throw new ArgumentNullException(nameof(culture));

        originalCulture = Thread.CurrentThread.CurrentCulture;
        originalUICulture = Thread.CurrentThread.CurrentUICulture;

        Thread.CurrentThread.CurrentCulture = culture;
        Thread.CurrentThread.CurrentUICulture = culture;
    }

    public void Dispose()
    {
        Thread.CurrentThread.CurrentCulture = originalCulture;
        Thread.CurrentThread.CurrentUICulture = originalUICulture;
    }
}

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

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

关于c# - 这是暂时改变当前线程文化的好方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5793000/

相关文章:

c# - 如何让普通的 WebRequest 异步且可等待?

c# - Azure.Search.Documents v11 中的 ContinuationToken 在哪里

c# - 图像序列到视频流?

.net - 迭代列表并删除 .NET 中的其他成员

python - Django 不创建翻译 .po 文件

c# - AsyncEx DeferralManager 用于等待事件处理程序

.net - MathML 或 OMML 到 PNG w/.NET?

.net - vb 判断一个Url是绝对的还是相对的

java - 我如何将我的应用程序在 Play 商店中的当前价格获取到每个位置以便在 textView 中显示

iOS:我可以在 APP 商店中分发不同国家/地区的不同 .ipa 文件吗