0

I'm trying to change a new thread CultureInfo like the sample below but:

  • Attempt1: SetCulture1() is not changing my thread
  • Attempt2: SetCulture2() I got the exception "System.InvalidOperationException: instance is read-only" (when set CurrencyDecimalSeparator)

    static void Main(string[] args)
    {
        Thread th = new Thread(thread_test);
    
        // nothing happens
        SetCulture1(th);
    
        // exception System.InvalidOperationException: instance is read-only
        SetCulture2(th);
    
        th.Start();
    }
    
    public static void SetCulture1(System.Threading.Thread thread)
    {
        var ci = new System.Globalization.CultureInfo("pt-BR");
        ci.NumberFormat.CurrencyDecimalSeparator = ".";
    
        thread.CurrentCulture = ci; // <-- after this culture info not change
    
        if (thread.CurrentCulture.NumberFormat.CurrencyDecimalSeparator != ".")
        {
            Console.WriteLine("Nothing happened");
            Console.ReadKey();
        }
    }
    
    public static void SetCulture2(System.Threading.Thread thread)
    {
        thread.CurrentCulture = new System.Globalization.CultureInfo("pt-BR");
        thread.CurrentCulture.NumberFormat.CurrencyDecimalSeparator = "."; // <-- exception throws here
    }
    
    static void thread_test()
    {
        Console.WriteLine("Culture: {0}", CultureInfo.CurrentCulture.DisplayName);
    }
    

I notice that before .net 4.6 this sample works. Did something changed in 4.6?

Thank you!

Julian
  • 886
  • 10
  • 21
idenardi
  • 600
  • 1
  • 6
  • 20
  • Possible duplicate of [Trying to set the decimal separator for the current language, getting "Instance is read Only"](https://stackoverflow.com/questions/24785689/trying-to-set-the-decimal-separator-for-the-current-language-getting-instance) – mjwills Jun 23 '18 at 22:50
  • After setting ci, CurrencyDecimalSeparator is not a "." – idenardi Jun 23 '18 at 23:07
  • 2
    You are right - it does appear to be a regression in 4.6 onwards. Setting it **does appear to work** (i.e. it has overwritten the culture inside the thread) but `get`ting it after `set`ting it returns the old value. Quite odd. You should https://www.microsoft.com/net/support/report-a-bug . – mjwills Jun 23 '18 at 23:21
  • Can't reproduce it on my side (.net 4.7.1) – Kevin Gosse Jun 24 '18 at 08:50
  • 1
    @KevinGosse Do you live in a culture where the decimal separator is `.`? If so, yes then `Nothing happened` won't show. You'll need to tweak the `.`s to be `,`s instead. – mjwills Jun 24 '18 at 21:26
  • @mjwills the behaviour [is documented](https://learn.microsoft.com/en-us/dotnet/api/system.threading.thread?redirectedfrom=MSDN&view=netframework-4.7.2#culture-and-threads). Whether it was documented 5 months ago is another matter as MSDN docs redirect to `learn.microsoft.com` now. – Panagiotis Kanavos Nov 13 '18 at 12:13
  • Thanks - good to see they documented it properly now @PanagiotisKanavos. – mjwills Nov 13 '18 at 12:15
  • @mjwills I think it's a matter of closing an existing loophole rather than documentation or new functionality. Similar to how one could modify the UI from a background thread back in 1.x even though it wasn't allowed, with unexpected results – Panagiotis Kanavos Nov 13 '18 at 12:27
  • Either way - it is nice that, given they changed the behaviour, they at least documented it @PanagiotisKanavos. It makes it much easier to understand, at the very least. – mjwills Nov 13 '18 at 12:29

1 Answers1

3

While this odd situation has no answer (Microsoft bug report), I found a work around setting DefaultThreadCurrentCulture at the start of my code (Main method):

        var ci = new System.Globalization.CultureInfo(System.Globalization.CultureInfo.CurrentCulture.LCID);
        ci.NumberFormat.CurrencyDecimalSeparator = ".";
        ci.NumberFormat.CurrencyGroupSeparator = ",";
        ci.NumberFormat.NumberDecimalSeparator = ".";
        ci.NumberFormat.NumberGroupSeparator = ",";
        ci.NumberFormat.PercentDecimalSeparator = ".";
        ci.NumberFormat.PercentGroupSeparator = ",";
        System.Globalization.CultureInfo.DefaultThreadCurrentCulture = ci;
        System.Globalization.CultureInfo.DefaultThreadCurrentUICulture = ci;
Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
idenardi
  • 600
  • 1
  • 6
  • 20
  • It has no answer because there's no bug. If there was, no application would work outside the US. And there wouldn't be any questions about `why can't I parse that double` or `how do I convert that date` either. People would have noticed – Panagiotis Kanavos Nov 13 '18 at 10:52
  • @PanagiotisKanavos, before .net 4.6 my question sample works. This problem happens only if you try to change any culture property before Start() the new thread.. – idenardi Nov 13 '18 at 11:04
  • You are modifying the culture *from another thread*, not before the thread starts. That's not supported. From the Thread object's [Culture and Threads](https://learn.microsoft.com/en-us/dotnet/api/system.threading.thread?redirectedfrom=MSDN&view=netframework-4.7.2#culture-and-threads) section: `The CurrentCulture and CurrentUICulture properties don't work reliably when used with any thread other than the current thread.`. – Panagiotis Kanavos Nov 13 '18 at 12:01
  • People aren't affected because they seldom work this way. Good practice is to pass the culture as a parameter. ASP.NET, Task threads come from pools and culture is managed by the runtime or middleware. Global changes are typically made in web.config or app.config. When custom cultures are needed, people use CustomAndRegionInfoBuilder [as shown here](https://stackoverflow.com/questions/1304507/create-custom-culture-in-asp-net) – Panagiotis Kanavos Nov 13 '18 at 12:06