May 19

Cultures, cultures and still more cultures…

Posted in .NET Basics C#      Comments Off on Cultures, cultures and still more cultures…

In one of my latest’s post on text and strings, reader John Meyer asks a couple of interesting questions:

Can you discuss any differences between these 2 ways of getting CultureInfo objects?

var culture1 = new CultureInfo(“en-US”);
var culture2 = CultureInfo.GetCultureInfo(“en-US”);

left one out of the previous comment, sorry:

var culture3 = CultureInfo.CreateSpecificCulture(“en-US”);

Before answering the question, I believe that it’s important to understand that cultures are grouped into three types: invariant, neutral and specific cultures. An invariant culture is, as its name says, invariant. You can think of this culture as something which… is nor neutral, nor specific :). The invariant culture’s name is the empty string  (“”) and, by default, it’s associated with the English language (but not with a specific country or region). You should only use this culture when you don’t require culture dependent results (ex.: persisting data that is not displayed to the users). So, you probably shouldn’t use this culture for operations that provide feedback to the user. The following code shows how to get a reference to an invariant culture object:

//both return an InvariantCulture object
var neutral1 = new CultureInfo( "" );
var neutral2 = CultureInfo.InvariantCulture;

In the previous examples of the text series, I believe that all the examples I’ve shown relied only on specific cultures CultureInfo objects. A specific culture is always associated with a language and a country or region. For instance, the following snippet creates a culture for the Portuguese language in Portugal:

var culture = new CultureInfo( "pt-PT" );

As you can see, specific cultures are always associated by a pair of chars which identify the language (“pt”) and the country or region (“PT”). Finally, we need to define the neutral culture concept. A neutral culture is a culture that is only associated with a language. In practice, that means that we only pass the language part during initialization of the object. In the following snippet, we’re creating a neutral culture object for the Portuguese language:

var culture = new CultureInfo( "pt" );

Since we’re discussing the existing CultureInfo classifications, there are a couple of interesting points before we start analyzing the previous methods:

  • The predefined cultures form a hierarchy, where a specific culture (ex.: “pt-PT”) is parented by a neutral culture (ex.: “pt”). The invariant culture is the parent of all neutral cultures. After getting a reference to a CultureInfo object, you can navigate through its hierarchy through its Parent property.Oh, and one more thing: the InvariantCulture parent is…drum roll…the InvariantCulture 🙂 (I’m mentioning this here because initially I thought it should be null…).
  • There are some operations which don’t *quite* work with neutral cultures. For instance, formatting a date will only work as expected when you’re using a specific culture. For instance, the next snippet shows what happens when you use the English neutral culture to format a date in the short date format:
var neutral1 = new CultureInfo( "en" );
Console.WriteLine(String.Format(neutral1, "{0:d}", DateTime.Now)); //5/19/20011
Console.WriteLine(String.Format(new CultureInfo( "en-US" ), "{0:d}", DateTime.Now));//5/19/20011
Console.WriteLine(String.Format(new CultureInfo( "en-GB" ), "{0:d}", DateTime.Now));//19/05/20011

Yes, it compiles and runs…but have  you noticed that the returned result isn’t really the one you’d expect if you live in the UK?

Ok, so I guess we’re ready to go…Lets start by understanding the difference between using the constructor and using the static GetCultureInfo method:

var culture1 = CultureInfo.GetCultureInfo( "pt-Pt" );
var culture2 = CultureInfo.GetCultureInfo( "pt-PT" );
Console.WriteLine(Object.ReferenceEquals(culture1, culture2));//true
var culture3 = new CultureInfo( "pt" );
var culture4 = new CultureInfo( "pt" );
Console.WriteLine(Object.ReferenceEquals(culture3, culture4));//false

I think the previous snippet shows what’s happening…whenever you use a constructor, you end up creating a new object. When you use the static GetCultureInfo method, you’ll end up getting a cached version of a CultureInfo object (if there exists one from a previous call). Notice that I’ve used the static Object.ReferenceEquals to make sure that I was getting the same instance from both method calls. It’s easy to understand that if you’ll be needing several instances of the same CultureInfo object, then you should probably use the GetCultureInfo method. Now, we’re left with the CreateSpecificCulture method…Take a look at the following snippet:

var neutral1 = CultureInfo.CreateSpecificCulture( "pt" );
var neutral2 = CultureInfo.GetCultureInfo( "pt" );

And now, a quick look at what the watch window shows during a debugging session:


As you can see, we use the same neutral culture *string*, but we end up with two different culture “types”. neutral1 references a *specific* CultureInfo instance and neutral2 does, indeed, “point” to a *neutral* CultureInfo object (you can easily test this by accessing the IsNeutralCulture property of the CultureInfo objects). As you can see, CreateSpecificCulture provides us with a way to get a reference to a specific culture object from a neutral culture string (btw, if you pass it a *specific* culture string, you’ll get the corresponding specific culture object). Notice that you don’t have any control over the specific culture returned. You only know that it will return a specific culture and there there are some cases where that behavior might end up confusing your users. I’d say that you can use this method, but only sparingly…

And I guess that’s it for now. Stay tuned for more.