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

2023-09-04 23:42:00 作者:人格分裂

我的工作,目前主要用于在美国是一个相当大的ASP.NET Web窗体应用程序。我们正处于部署到世界,这当然意味着我们目前正在本地化的应用程序的所有领域的其他部分的过程。一般来说我们的做法是在每个请求支持基于当前用户的语言环境的正确格式和资源开采的开头设置当前线程的的CurrentCulture和的CurrentUICulture属性。

I work on a fairly large ASP .NET Web Forms application that is currently used primarily in the United States. We are in the process of rolling it out to other parts of the world, which of course means we are currently working on localizing all areas of the application. Generally speaking our approach has been to set the current thread's CurrentCulture and CurrentUICulture properties at the beginning of each request to support the proper formatting and resource extraction based on the current user's locale.

在某些情况下,然而,我们有必要运行使用比当前用户的文化的其他文化的code进行特定比特。例如,用户A住在德国,在一家公司做业务,在法国其他公司。当用户A希望为那些法国企业之一,创建发票(PDF),我们希望该发票代code与FR-FR文化比去德文化的运行,而

In some cases, however, we have a need to run a certain bit of a code using a culture other than the culture of the current user. For example, 'User A' lives in Germany but works for a company that does business with other companies in France. When 'User A' wants to create an invoice (PDF) for one of those French companies, we want that invoice generation code to run with the 'fr-FR' culture rather than the 'de-DE' culture.

我认为很容易这样做的几种方法,并想知道如果我正确地将这个问题。我的主要问题是各地的性能和线程安全。

I've considered a couple ways of doing this easily and am wondering if I'm going about this correctly. My main concerns are around performance and thread safety.

一种方法涉及设计用于运行给定的任务与所提供的文化的静态方法。事情是这样的:

One approach involves a static method designed to run a given task with a provided culture. Something like this:

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

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

This method could then be invoked like this:

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

我还考虑建立一个类实现IDisposable这将是负责设置线程的文化,在它的构造函数,然后返回原来的文化早在Dispose方法,所以你可以把它叫做是这样的:

I've also considered creating a class that implements IDisposable that would be responsible for setting the thread culture in it's ctor and then returning the original cultures back in the Dispose method, so you could call it like this:

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

我要对这个都错了?其中,如果有的话,这些方法是preferable?

Am I going about this all wrong? Which, if any of these approaches is preferable?

推荐答案

我喜欢使用办法。我还创建一个扩展方法使事情更好地阅读:

I like the using approach. I'd also create an extension method to make things read better:

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

事情是这样的:

Something like this:

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

或者,如果它总是你的客户对象,谁设置的文化,另一种扩展方法将提高抽象更进一步:

Or, if it's always your customer object who sets the culture, another extension method would raise the abstraction even further:

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