Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
334 views
in Technique[技术] by (71.8m points)

c# - Keep CurrentCulture in async/await

I have following pseudo-code

string GetData()
{
  var steps = new List<Task<string>>
  {
    DoSomeStep(),
    DoSomeStep2()
  };

  await Task.WhenAll(steps);

  return SomeResourceManagerProxy.RetrieveValuesForLocalizedStrings( steps.Select(s => s.Result) );

}

This method is called from WebService, where I set Thread.CurrentUICulture according to user's browser settings.

After await, the CurrentUICulture is lost (I run on different thread).

I have solved the issue with following:

    public class MyAwaiter<T> : INotifyCompletion
    {
        private TaskAwaiter<T> waiter;
        private CultureInfo culture;

        public MyAwaiter(TaskAwaiter<T> waiter)
        {
            this.waiter = waiter;
        }

        public PreserveCultureAwaiter<T> GetAwaiter() { return this; }

        public bool IsCompleted { get { return waiter.IsCompleted; } }

        public void OnCompleted(Action continuation)
        {
            culture = Thread.CurrentThread.CurrentUICulture;
            waiter.OnCompleted(continuation);
        }

        public T GetResult()
        {
            Thread.CurrentThread.CurrentUICulture = culture;
            return waiter.GetResult();
        }
    }

    public static MyAwaiter<T> KeepCulture<T>(this Task<T> task)
    {
        return new MyAwaiter<T>(task.GetAwaiter());
    }

...

    await Task.WhenAll(steps).KeepCulture();

This has one drawback - need for remembering to call KeepCulture() on every task that is being awaited. (I have also some extension method to keep the UI culture in task).

Is there any easier way how to preserve UI culture?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Culture does not flow in the .NET Framework, a very notorious problem. It is very hard to solve on Windows, culture is an unmanaged property of a thread so the CLR can't ensure it is always set correctly. That makes tinkering with the CurrentCulture on the main thread a big fat mistake. The bugs you get are very hard to diagnose. Like a SortedList you create on one thread that suddenly isn't sorted anymore on another. Yuck.

Microsoft did something about it in .NET 4.5, they added the CultureInfo.DefaultThreadCurrentCulture property. Also DefaultThreadCurrentUICulture. That still does not guarantee it will be set correctly, unmanaged code you call can change it and the CLR cannot do anything about it. In other words, a bug will be much harder to diagnose. But at least you have some idea when it might change.


UPDATE: this problem was fixed thoroughly in .NET 4.6, culture now flows from one thread to another and the CultureInfo.DefaultThreadCurrentCulture hack is not longer necessary nor useful. Documented in the MSDN article for CultureInfo.CurrentCulture. Details as written right now do not appear to be entirely correct, it always flowed when I tested it and DefaultThreadCurrentCulture appear to play no role at all anymore.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...