使用任务创建者的CurrentCulture设置来执行任务

6
我有一个应用程序,我们使用任务(Tasks)来完成。我们还修改了CultureInfo(使用的是EN-US语言,但保留日期/数字格式),并且我们使用的是.Net 4.0。
该应用程序有很多线程和任务,并且我们有一个工厂用于创建Task/Threads。
对于线程,我们有以下代码,以确保每个线程都在正确的CurrentCulture下启动:
//This is basically only the constructor, but it describe well how we create the Thread:
public MonitoredThread(ThreadStart threadStart, string name, bool isBackground = false)
{
    m_threadStart = threadStart;
    m_name = name;
    m_isBackground = isBackground;
    Thread = new Thread(ThreadWorker)
    {
        Name = name,
        IsBackground = isBackground,
        CurrentCulture = CustomCultureInfo.CurrentCulture,
        CurrentUICulture = CustomCultureInfo.CurrentCulture
    };
}

但是对于任务,我不知道如何实现这种机制:
public static Task ExecuteTask(Action action, string name)
{
    MonitoredTask task = new MonitoredTask(action, name);
    return Task.Factory.StartNew(task.TaskWorker);
}

有什么想法吗?

TaskWorker 是什么类型? - Johannes Wanzek
MonitoredTask是一个自定义类,代表一个Task(我们跟踪它们何时开始、何时结束等等...)。TaskWorker是一个属性,可以访问由该类映射的Task - J4N
出现了一个错误,TaskWorker 是我们在构造函数参数中提供的操作。 - J4N
虽然晚了,但这是最佳答案:https://dev59.com/c3RB5IYBdhLWcg3w6bYE#7536117 - G J
@GauravSinghJantwal "我们使用 .Net 4.0。" - J4N
3个回答

5

我不确定您是否真的需要一个MonitoredTask来完成这个任务。您可以使用闭包捕获自定义区域设置:

public static Task ExecuteTask(Action action, string name)
{
   var customCulture = CustomCultureInfo.CurrentCulture;
   return Task.Factory.StartNew(() => 
   {
       // use customCulture variable as needed
      // inside the generated task.
   });
}

另一种做法是使用正确的重载(Action<object>Func<object, TResult>)将当前文化作为 对象状态 传递:

public static Task ExecuteTask(Action action, string name)
{
   var customCulture = CustomCultureInfo.CurrentCulture;
   return Task.Factory.StartNew((obj) => 
   {
       var culture = (CultureInfo) obj;
       // use customCulture variable as needed
      // inside the generated task.
   }, customCulture);
}

我肯定会选择前者。 有关闭包的更多内容,请参见.NET中的“闭包”是什么?

实际上,MonitoredTask已经包装了“action”,而提供的Action“TaskWorker”已经进行了一些更改(例如注册新任务已启动,记录执行期间发生的任何错误)。因此,我能够直接在这部分设置CurrentCulture。很抱歉浪费了您的时间,但是您指引了我正确的方向 :) - J4N

3
从 .Net 4.5 开始,您可以为当前应用程序域中的所有线程设置默认文化(MSDN):
CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;

这样,您的应用程序中所有任务和线程都有统一的文化。

1

补充一下@Yuval Itzchakov的回答,我通常会为TaskFactory类创建一些扩展方法,以保留语言环境(我也会添加一个接收操作的方法,将任何给定的属性设置到执行线程中:

#region StartNewWithPersistedCulture methods

public static Task<TResult> StartNewWithPersistedCulture<TResult>(
    this TaskFactory taskFactory, Func<TResult> function, CancellationToken cancellationToken = default (CancellationToken), TaskCreationOptions creationOptions = default (TaskCreationOptions))
{
    if (taskFactory == null) throw new ArgumentNullException("taskFactory");
    if (function == null) throw new ArgumentNullException("function");

    var currentCulture = Thread.CurrentThread.CurrentCulture;
    var currentUICulture = Thread.CurrentThread.CurrentUICulture;
    return taskFactory.StartNew(
        () =>
        {
            Thread.CurrentThread.CurrentCulture = currentCulture;
            Thread.CurrentThread.CurrentUICulture = currentUICulture;

            return function();
        }, cancellationToken, creationOptions, TaskScheduler.Default);
}

public static Task StartNewWithPersistedCulture(
    this TaskFactory taskFactory, Action action, CancellationToken cancellationToken = default (CancellationToken), TaskCreationOptions creationOptions = default (TaskCreationOptions))
{
    if (taskFactory == null) throw new ArgumentNullException("taskFactory");
    if (action == null) throw new ArgumentNullException("action");

    var currentCulture = Thread.CurrentThread.CurrentCulture;
    var currentUICulture = Thread.CurrentThread.CurrentUICulture;
    return taskFactory.StartNew(
        () =>
        {
            Thread.CurrentThread.CurrentCulture = currentCulture;
            Thread.CurrentThread.CurrentUICulture = currentUICulture;

            action();
        }, cancellationToken, creationOptions, TaskScheduler.Default);
} 

#endregion

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接