0

Let's say I have a class with a property that returns an array of strings.

public static string[] MyStrings
{
    get { return new string[] { "Foo", "Bar" }; }
}

Will this create multiple instances of MyStrings every time it is referenced? Are there compiler optimizations that effectively make it a singleton, or do I have to explicitly do something like this:

private static string[] _myStrings = new string[] { "Foo", "Bar" };
public static string[] MyStrings
{
    get { return _myStrings; }
}
  • using 'static' means only 1 object will ever be created and it would be created implicitly. – NoChance Jan 25 at 19:57
  • @NoChance For classes, yes, but not for properties. All static means on a property is that it is available statically on the type without needing an instance. dotnetfiddle.net/1Gs18K – Jacob Stamm Jan 25 at 20:25
  • Using 'new' with 'static', while valid is a bit confusing sometimes. My understanding was that a "static" = 1 copy. – NoChance Jan 25 at 20:48
  • 4
    Note that your optimization is extremely dangerous; anyone at all can change the contents of an array that they can read! That is, someone can say MyStrings()[0] = "blah"; and now every other caller to MyStrings(), past and future, gets the change. This is why returning an array is often the wrong thing to do. – Eric Lippert Jan 25 at 23:41
  • @EricLippert Thanks for the warning, you're right. Do you have a recommended alternative for cases like this? – Jacob Stamm Jan 28 at 14:45
1

Will this create multiple instances of MyStrings every time it is referenced?

It will reuse the strings objects for the literals "Foo", and "Bar".

However, by definition of the new operator, the language is forced to create a new array object each time the getter is invoked, i.e. the new expression is run.

By definition, while string literals that match must be the same object:

"a" must == "a" 

however,

new String ( "a" ) must != new String ( "a" )

new String [] { "a", "b" } must != new String [] { "a", "b" }

where here I'm using == and != for reference equality, so by "must !=" I mean these must be different (string or string array) objects.

That execution of two new expressions must each create a brand new object (i.e. cannot not return a shared object) goes to the definition of new in C# and Java — this holds for two executions of new even of identical arguments, and, even when constructing an instance of an immutable class, and, even when the two executions are the same expression (same line of code) run twice.

To eliminate the array creation you have to do something like you're suggesting later.

Another approach (though probably not practical here) is to use a factory method instead of new as they have more freedom, e.g. to return shared instances (or even return subclass), whereas new does not have this latitude.


While compiler optimization is not inconceivable, it would have issues.  For one, it would have to create the first/initial object, and store and relocate that for reuse later.  While this is done automatically for string literals, string literals have well understood behavior so, for example, they can be pre-created with impunity, and they don't require finalizers, further the definition of string literals suggests program lifetime anyway, so the runtime stores the string literals in global variables for later use — doing this in more general cases can be problematic.  Consider also that while string literals are immutable, string arrays are mutable, so analysis would have to take into account potential tests for object equality/inequality as well as potential mutations to the returned array (which would make it un-shareable).

More likely, the compiler optimization here that would help reduce the cost of these allocations is one that transforms heap allocation into stack allocation.

All in all, the alternative you suggest is likely to be the most effective; it is also perfectly readable IMHO.

  • What do you think of using a get-only automatic property that is auto-initialized instead of being backed by a field (assuming C# 6+, of course)? private static string[] MyStrings { get; } = new string[] { "Foo", "Bar" }; Is the behavior the same, and do you consider it better or worse than the alternative in my original question? – Jacob Stamm Jan 25 at 20:30
  • I think that's even better. Just one last thing, be aware that string array is mutable, so the consuming client (perhaps you) could alter parts of your original and subsequent consumers would get that altered copy (same is true for the explicit backing field)... (C# has read only collections, though, which might be more appropriate, depending on context). – Erik Eidt Jan 25 at 20:49
  • @ErikEidt: new String ( "a" ) != new String ( "a" ) does not compile. I'm not sure what you intended to be there. – Brian Jan 28 at 20:20
  • @Brian, what I said was that the object created by one new cannot be the same object as created another new. I also never wrote new String ( "a" ) != new String ( "a" ), that would be misleading, especially in C# due to the operator overloading of != and == for string. What I did say had several fragments of code that require more context to be run. – Erik Eidt Jan 28 at 20:42
  • @Brian, if you want to put this to a test with the compiler and run it, put the following (in a method in a class): if ( (object) new String ( "a" ) != (object) new String ( "a" ) ) Console.WriteLine ( "different objects" ); else Console.WriteLine ( "same object" );. Casting to object will test reference equality, and, putting it inside an statement will make it a legal statement. – Erik Eidt Jan 28 at 20:46

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.